xref: /openbmc/linux/tools/perf/util/probe-file.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
292f6c72eSMasami Hiramatsu /*
392f6c72eSMasami Hiramatsu  * probe-file.c : operate ftrace k/uprobe events files
492f6c72eSMasami Hiramatsu  *
592f6c72eSMasami Hiramatsu  * Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
692f6c72eSMasami Hiramatsu  */
7a43783aeSArnaldo Carvalho de Melo #include <errno.h>
8c23c2a0fSArnaldo Carvalho de Melo #include <fcntl.h>
97a8ef4c4SArnaldo Carvalho de Melo #include <sys/stat.h>
107a8ef4c4SArnaldo Carvalho de Melo #include <sys/types.h>
11dd975497SMasami Hiramatsu #include <sys/uio.h>
127a8ef4c4SArnaldo Carvalho de Melo #include <unistd.h>
137f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
1440f3b2d2SArnaldo Carvalho de Melo #include "namespaces.h"
1592f6c72eSMasami Hiramatsu #include "event.h"
1692f6c72eSMasami Hiramatsu #include "strlist.h"
178ec20b17SArnaldo Carvalho de Melo #include "strfilter.h"
1892f6c72eSMasami Hiramatsu #include "debug.h"
1936f3f450SArnaldo Carvalho de Melo #include "build-id.h"
20fac583fdSArnaldo Carvalho de Melo #include "dso.h"
2192f6c72eSMasami Hiramatsu #include "color.h"
2292f6c72eSMasami Hiramatsu #include "symbol.h"
23fa0d9846SArnaldo Carvalho de Melo #include "strbuf.h"
24fbf99625SJiri Olsa #include <api/fs/tracing_path.h>
250808b3d5SMasami Hiramatsu #include <api/fs/fs.h>
2692f6c72eSMasami Hiramatsu #include "probe-event.h"
2792f6c72eSMasami Hiramatsu #include "probe-file.h"
2892f6c72eSMasami Hiramatsu #include "session.h"
293b1f8311SAlexis Berlemont #include "perf_regs.h"
30a067558eSArnaldo Carvalho de Melo #include "string2.h"
3192f6c72eSMasami Hiramatsu 
322e1f8f78SRavi Bangoria /* 4096 - 2 ('\n' + '\0') */
332e1f8f78SRavi Bangoria #define MAX_CMDLEN 4094
3492f6c72eSMasami Hiramatsu 
print_common_warning(int err,bool readwrite)350808b3d5SMasami Hiramatsu static bool print_common_warning(int err, bool readwrite)
360808b3d5SMasami Hiramatsu {
370808b3d5SMasami Hiramatsu 	if (err == -EACCES)
380808b3d5SMasami Hiramatsu 		pr_warning("No permission to %s tracefs.\nPlease %s\n",
390808b3d5SMasami Hiramatsu 			   readwrite ? "write" : "read",
400808b3d5SMasami Hiramatsu 			   readwrite ? "run this command again with sudo." :
410808b3d5SMasami Hiramatsu 				       "try 'sudo mount -o remount,mode=755 /sys/kernel/tracing/'");
420808b3d5SMasami Hiramatsu 	else
430808b3d5SMasami Hiramatsu 		return false;
440808b3d5SMasami Hiramatsu 
450808b3d5SMasami Hiramatsu 	return true;
460808b3d5SMasami Hiramatsu }
470808b3d5SMasami Hiramatsu 
print_configure_probe_event(int kerr,int uerr)480808b3d5SMasami Hiramatsu static bool print_configure_probe_event(int kerr, int uerr)
490808b3d5SMasami Hiramatsu {
500808b3d5SMasami Hiramatsu 	const char *config, *file;
510808b3d5SMasami Hiramatsu 
520808b3d5SMasami Hiramatsu 	if (kerr == -ENOENT && uerr == -ENOENT) {
530808b3d5SMasami Hiramatsu 		file = "{k,u}probe_events";
540808b3d5SMasami Hiramatsu 		config = "CONFIG_KPROBE_EVENTS=y and CONFIG_UPROBE_EVENTS=y";
550808b3d5SMasami Hiramatsu 	} else if (kerr == -ENOENT) {
560808b3d5SMasami Hiramatsu 		file = "kprobe_events";
570808b3d5SMasami Hiramatsu 		config = "CONFIG_KPROBE_EVENTS=y";
580808b3d5SMasami Hiramatsu 	} else if (uerr == -ENOENT) {
590808b3d5SMasami Hiramatsu 		file = "uprobe_events";
600808b3d5SMasami Hiramatsu 		config = "CONFIG_UPROBE_EVENTS=y";
610808b3d5SMasami Hiramatsu 	} else
620808b3d5SMasami Hiramatsu 		return false;
630808b3d5SMasami Hiramatsu 
640808b3d5SMasami Hiramatsu 	if (!debugfs__configured() && !tracefs__configured())
650808b3d5SMasami Hiramatsu 		pr_warning("Debugfs or tracefs is not mounted\n"
660808b3d5SMasami Hiramatsu 			   "Please try 'sudo mount -t tracefs nodev /sys/kernel/tracing/'\n");
670808b3d5SMasami Hiramatsu 	else
680808b3d5SMasami Hiramatsu 		pr_warning("%s/%s does not exist.\nPlease rebuild kernel with %s.\n",
690808b3d5SMasami Hiramatsu 			   tracing_path_mount(), file, config);
700808b3d5SMasami Hiramatsu 
710808b3d5SMasami Hiramatsu 	return true;
720808b3d5SMasami Hiramatsu }
730808b3d5SMasami Hiramatsu 
print_open_warning(int err,bool uprobe,bool readwrite)740808b3d5SMasami Hiramatsu static void print_open_warning(int err, bool uprobe, bool readwrite)
7592f6c72eSMasami Hiramatsu {
7692f6c72eSMasami Hiramatsu 	char sbuf[STRERR_BUFSIZE];
7792f6c72eSMasami Hiramatsu 
780808b3d5SMasami Hiramatsu 	if (print_common_warning(err, readwrite))
790808b3d5SMasami Hiramatsu 		return;
8092f6c72eSMasami Hiramatsu 
810808b3d5SMasami Hiramatsu 	if (print_configure_probe_event(uprobe ? 0 : err, uprobe ? err : 0))
820808b3d5SMasami Hiramatsu 		return;
8392f6c72eSMasami Hiramatsu 
840808b3d5SMasami Hiramatsu 	pr_warning("Failed to open %s/%cprobe_events: %s\n",
850808b3d5SMasami Hiramatsu 		   tracing_path_mount(), uprobe ? 'u' : 'k',
86c8b5f2c9SArnaldo Carvalho de Melo 		   str_error_r(-err, sbuf, sizeof(sbuf)));
8792f6c72eSMasami Hiramatsu }
8892f6c72eSMasami Hiramatsu 
print_both_open_warning(int kerr,int uerr,bool readwrite)890808b3d5SMasami Hiramatsu static void print_both_open_warning(int kerr, int uerr, bool readwrite)
9092f6c72eSMasami Hiramatsu {
9192f6c72eSMasami Hiramatsu 	char sbuf[STRERR_BUFSIZE];
920808b3d5SMasami Hiramatsu 
930808b3d5SMasami Hiramatsu 	if (kerr == uerr && print_common_warning(kerr, readwrite))
940808b3d5SMasami Hiramatsu 		return;
950808b3d5SMasami Hiramatsu 
960808b3d5SMasami Hiramatsu 	if (print_configure_probe_event(kerr, uerr))
970808b3d5SMasami Hiramatsu 		return;
980808b3d5SMasami Hiramatsu 
990808b3d5SMasami Hiramatsu 	if (kerr < 0)
1000808b3d5SMasami Hiramatsu 		pr_warning("Failed to open %s/kprobe_events: %s.\n",
1010808b3d5SMasami Hiramatsu 			   tracing_path_mount(),
102c8b5f2c9SArnaldo Carvalho de Melo 			   str_error_r(-kerr, sbuf, sizeof(sbuf)));
1030808b3d5SMasami Hiramatsu 	if (uerr < 0)
1040808b3d5SMasami Hiramatsu 		pr_warning("Failed to open %s/uprobe_events: %s.\n",
1050808b3d5SMasami Hiramatsu 			   tracing_path_mount(),
106c8b5f2c9SArnaldo Carvalho de Melo 			   str_error_r(-uerr, sbuf, sizeof(sbuf)));
10792f6c72eSMasami Hiramatsu }
10892f6c72eSMasami Hiramatsu 
open_trace_file(const char * trace_file,bool readwrite)109e491bc2fSNaveen N. Rao int open_trace_file(const char *trace_file, bool readwrite)
11092f6c72eSMasami Hiramatsu {
11192f6c72eSMasami Hiramatsu 	char buf[PATH_MAX];
11292f6c72eSMasami Hiramatsu 	int ret;
11392f6c72eSMasami Hiramatsu 
11417c257e8SArnaldo Carvalho de Melo 	ret = e_snprintf(buf, PATH_MAX, "%s/%s", tracing_path_mount(), trace_file);
11592f6c72eSMasami Hiramatsu 	if (ret >= 0) {
11692f6c72eSMasami Hiramatsu 		pr_debug("Opening %s write=%d\n", buf, readwrite);
11792f6c72eSMasami Hiramatsu 		if (readwrite && !probe_event_dry_run)
11892f6c72eSMasami Hiramatsu 			ret = open(buf, O_RDWR | O_APPEND, 0);
11992f6c72eSMasami Hiramatsu 		else
12092f6c72eSMasami Hiramatsu 			ret = open(buf, O_RDONLY, 0);
12192f6c72eSMasami Hiramatsu 
12292f6c72eSMasami Hiramatsu 		if (ret < 0)
12392f6c72eSMasami Hiramatsu 			ret = -errno;
12492f6c72eSMasami Hiramatsu 	}
12592f6c72eSMasami Hiramatsu 	return ret;
12692f6c72eSMasami Hiramatsu }
12792f6c72eSMasami Hiramatsu 
open_kprobe_events(bool readwrite)12892f6c72eSMasami Hiramatsu static int open_kprobe_events(bool readwrite)
12992f6c72eSMasami Hiramatsu {
130e491bc2fSNaveen N. Rao 	return open_trace_file("kprobe_events", readwrite);
13192f6c72eSMasami Hiramatsu }
13292f6c72eSMasami Hiramatsu 
open_uprobe_events(bool readwrite)13392f6c72eSMasami Hiramatsu static int open_uprobe_events(bool readwrite)
13492f6c72eSMasami Hiramatsu {
135e491bc2fSNaveen N. Rao 	return open_trace_file("uprobe_events", readwrite);
13692f6c72eSMasami Hiramatsu }
13792f6c72eSMasami Hiramatsu 
probe_file__open(int flag)13892f6c72eSMasami Hiramatsu int probe_file__open(int flag)
13992f6c72eSMasami Hiramatsu {
14092f6c72eSMasami Hiramatsu 	int fd;
14192f6c72eSMasami Hiramatsu 
14292f6c72eSMasami Hiramatsu 	if (flag & PF_FL_UPROBE)
14392f6c72eSMasami Hiramatsu 		fd = open_uprobe_events(flag & PF_FL_RW);
14492f6c72eSMasami Hiramatsu 	else
14592f6c72eSMasami Hiramatsu 		fd = open_kprobe_events(flag & PF_FL_RW);
14692f6c72eSMasami Hiramatsu 	if (fd < 0)
1470808b3d5SMasami Hiramatsu 		print_open_warning(fd, flag & PF_FL_UPROBE, flag & PF_FL_RW);
14892f6c72eSMasami Hiramatsu 
14992f6c72eSMasami Hiramatsu 	return fd;
15092f6c72eSMasami Hiramatsu }
15192f6c72eSMasami Hiramatsu 
probe_file__open_both(int * kfd,int * ufd,int flag)15292f6c72eSMasami Hiramatsu int probe_file__open_both(int *kfd, int *ufd, int flag)
15392f6c72eSMasami Hiramatsu {
15492f6c72eSMasami Hiramatsu 	if (!kfd || !ufd)
15592f6c72eSMasami Hiramatsu 		return -EINVAL;
15692f6c72eSMasami Hiramatsu 
15792f6c72eSMasami Hiramatsu 	*kfd = open_kprobe_events(flag & PF_FL_RW);
15892f6c72eSMasami Hiramatsu 	*ufd = open_uprobe_events(flag & PF_FL_RW);
15992f6c72eSMasami Hiramatsu 	if (*kfd < 0 && *ufd < 0) {
1600808b3d5SMasami Hiramatsu 		print_both_open_warning(*kfd, *ufd, flag & PF_FL_RW);
16192f6c72eSMasami Hiramatsu 		return *kfd;
16292f6c72eSMasami Hiramatsu 	}
16392f6c72eSMasami Hiramatsu 
16492f6c72eSMasami Hiramatsu 	return 0;
16592f6c72eSMasami Hiramatsu }
16692f6c72eSMasami Hiramatsu 
16792f6c72eSMasami Hiramatsu /* Get raw string list of current kprobe_events  or uprobe_events */
probe_file__get_rawlist(int fd)16892f6c72eSMasami Hiramatsu struct strlist *probe_file__get_rawlist(int fd)
16992f6c72eSMasami Hiramatsu {
1700325862dSColin Ian King 	int ret, idx, fddup;
17192f6c72eSMasami Hiramatsu 	FILE *fp;
17292f6c72eSMasami Hiramatsu 	char buf[MAX_CMDLEN];
17392f6c72eSMasami Hiramatsu 	char *p;
17492f6c72eSMasami Hiramatsu 	struct strlist *sl;
17592f6c72eSMasami Hiramatsu 
176421fd084SWang Nan 	if (fd < 0)
177421fd084SWang Nan 		return NULL;
178421fd084SWang Nan 
17992f6c72eSMasami Hiramatsu 	sl = strlist__new(NULL, NULL);
18060ebc159SArnaldo Carvalho de Melo 	if (sl == NULL)
18160ebc159SArnaldo Carvalho de Melo 		return NULL;
18292f6c72eSMasami Hiramatsu 
1830325862dSColin Ian King 	fddup = dup(fd);
1840325862dSColin Ian King 	if (fddup < 0)
1850325862dSColin Ian King 		goto out_free_sl;
1860325862dSColin Ian King 
1870325862dSColin Ian King 	fp = fdopen(fddup, "r");
1880325862dSColin Ian King 	if (!fp)
1890325862dSColin Ian King 		goto out_close_fddup;
1900325862dSColin Ian King 
19192f6c72eSMasami Hiramatsu 	while (!feof(fp)) {
19292f6c72eSMasami Hiramatsu 		p = fgets(buf, MAX_CMDLEN, fp);
19392f6c72eSMasami Hiramatsu 		if (!p)
19492f6c72eSMasami Hiramatsu 			break;
19592f6c72eSMasami Hiramatsu 
19692f6c72eSMasami Hiramatsu 		idx = strlen(p) - 1;
19792f6c72eSMasami Hiramatsu 		if (p[idx] == '\n')
19892f6c72eSMasami Hiramatsu 			p[idx] = '\0';
19992f6c72eSMasami Hiramatsu 		ret = strlist__add(sl, buf);
20092f6c72eSMasami Hiramatsu 		if (ret < 0) {
20192f6c72eSMasami Hiramatsu 			pr_debug("strlist__add failed (%d)\n", ret);
20260ebc159SArnaldo Carvalho de Melo 			goto out_close_fp;
20392f6c72eSMasami Hiramatsu 		}
20492f6c72eSMasami Hiramatsu 	}
20592f6c72eSMasami Hiramatsu 	fclose(fp);
20692f6c72eSMasami Hiramatsu 
20792f6c72eSMasami Hiramatsu 	return sl;
2080325862dSColin Ian King 
20960ebc159SArnaldo Carvalho de Melo out_close_fp:
21060ebc159SArnaldo Carvalho de Melo 	fclose(fp);
21160ebc159SArnaldo Carvalho de Melo 	goto out_free_sl;
2120325862dSColin Ian King out_close_fddup:
2130325862dSColin Ian King 	close(fddup);
2140325862dSColin Ian King out_free_sl:
2150325862dSColin Ian King 	strlist__delete(sl);
2160325862dSColin Ian King 	return NULL;
21792f6c72eSMasami Hiramatsu }
21892f6c72eSMasami Hiramatsu 
__probe_file__get_namelist(int fd,bool include_group)21992f6c72eSMasami Hiramatsu static struct strlist *__probe_file__get_namelist(int fd, bool include_group)
22092f6c72eSMasami Hiramatsu {
22192f6c72eSMasami Hiramatsu 	char buf[128];
22292f6c72eSMasami Hiramatsu 	struct strlist *sl, *rawlist;
22392f6c72eSMasami Hiramatsu 	struct str_node *ent;
22492f6c72eSMasami Hiramatsu 	struct probe_trace_event tev;
22592f6c72eSMasami Hiramatsu 	int ret = 0;
22692f6c72eSMasami Hiramatsu 
22792f6c72eSMasami Hiramatsu 	memset(&tev, 0, sizeof(tev));
22892f6c72eSMasami Hiramatsu 	rawlist = probe_file__get_rawlist(fd);
22992f6c72eSMasami Hiramatsu 	if (!rawlist)
23092f6c72eSMasami Hiramatsu 		return NULL;
23192f6c72eSMasami Hiramatsu 	sl = strlist__new(NULL, NULL);
232602a1f4dSArnaldo Carvalho de Melo 	strlist__for_each_entry(ent, rawlist) {
23392f6c72eSMasami Hiramatsu 		ret = parse_probe_trace_command(ent->s, &tev);
23492f6c72eSMasami Hiramatsu 		if (ret < 0)
23592f6c72eSMasami Hiramatsu 			break;
23692f6c72eSMasami Hiramatsu 		if (include_group) {
23792f6c72eSMasami Hiramatsu 			ret = e_snprintf(buf, 128, "%s:%s", tev.group,
23892f6c72eSMasami Hiramatsu 					tev.event);
23992f6c72eSMasami Hiramatsu 			if (ret >= 0)
24092f6c72eSMasami Hiramatsu 				ret = strlist__add(sl, buf);
24192f6c72eSMasami Hiramatsu 		} else
24292f6c72eSMasami Hiramatsu 			ret = strlist__add(sl, tev.event);
24392f6c72eSMasami Hiramatsu 		clear_probe_trace_event(&tev);
2446b8d68f1SMasami Hiramatsu 		/* Skip if there is same name multi-probe event in the list */
2456b8d68f1SMasami Hiramatsu 		if (ret == -EEXIST)
2466b8d68f1SMasami Hiramatsu 			ret = 0;
24792f6c72eSMasami Hiramatsu 		if (ret < 0)
24892f6c72eSMasami Hiramatsu 			break;
24992f6c72eSMasami Hiramatsu 	}
25092f6c72eSMasami Hiramatsu 	strlist__delete(rawlist);
25192f6c72eSMasami Hiramatsu 
25292f6c72eSMasami Hiramatsu 	if (ret < 0) {
25392f6c72eSMasami Hiramatsu 		strlist__delete(sl);
25492f6c72eSMasami Hiramatsu 		return NULL;
25592f6c72eSMasami Hiramatsu 	}
25692f6c72eSMasami Hiramatsu 	return sl;
25792f6c72eSMasami Hiramatsu }
25892f6c72eSMasami Hiramatsu 
25992f6c72eSMasami Hiramatsu /* Get current perf-probe event names */
probe_file__get_namelist(int fd)26092f6c72eSMasami Hiramatsu struct strlist *probe_file__get_namelist(int fd)
26192f6c72eSMasami Hiramatsu {
26292f6c72eSMasami Hiramatsu 	return __probe_file__get_namelist(fd, false);
26392f6c72eSMasami Hiramatsu }
26492f6c72eSMasami Hiramatsu 
probe_file__add_event(int fd,struct probe_trace_event * tev)26592f6c72eSMasami Hiramatsu int probe_file__add_event(int fd, struct probe_trace_event *tev)
26692f6c72eSMasami Hiramatsu {
26792f6c72eSMasami Hiramatsu 	int ret = 0;
26892f6c72eSMasami Hiramatsu 	char *buf = synthesize_probe_trace_command(tev);
26992f6c72eSMasami Hiramatsu 	char sbuf[STRERR_BUFSIZE];
27092f6c72eSMasami Hiramatsu 
27192f6c72eSMasami Hiramatsu 	if (!buf) {
27292f6c72eSMasami Hiramatsu 		pr_debug("Failed to synthesize probe trace event.\n");
27392f6c72eSMasami Hiramatsu 		return -EINVAL;
27492f6c72eSMasami Hiramatsu 	}
27592f6c72eSMasami Hiramatsu 
27692f6c72eSMasami Hiramatsu 	pr_debug("Writing event: %s\n", buf);
27792f6c72eSMasami Hiramatsu 	if (!probe_event_dry_run) {
2786ed0720aSMasami Hiramatsu 		if (write(fd, buf, strlen(buf)) < (int)strlen(buf)) {
27992f6c72eSMasami Hiramatsu 			ret = -errno;
28092f6c72eSMasami Hiramatsu 			pr_warning("Failed to write event: %s\n",
281c8b5f2c9SArnaldo Carvalho de Melo 				   str_error_r(errno, sbuf, sizeof(sbuf)));
28292f6c72eSMasami Hiramatsu 		}
28392f6c72eSMasami Hiramatsu 	}
28492f6c72eSMasami Hiramatsu 	free(buf);
28592f6c72eSMasami Hiramatsu 
28692f6c72eSMasami Hiramatsu 	return ret;
28792f6c72eSMasami Hiramatsu }
28892f6c72eSMasami Hiramatsu 
__del_trace_probe_event(int fd,struct str_node * ent)28992f6c72eSMasami Hiramatsu static int __del_trace_probe_event(int fd, struct str_node *ent)
29092f6c72eSMasami Hiramatsu {
29192f6c72eSMasami Hiramatsu 	char *p;
29292f6c72eSMasami Hiramatsu 	char buf[128];
29392f6c72eSMasami Hiramatsu 	int ret;
29492f6c72eSMasami Hiramatsu 
29592f6c72eSMasami Hiramatsu 	/* Convert from perf-probe event to trace-probe event */
29692f6c72eSMasami Hiramatsu 	ret = e_snprintf(buf, 128, "-:%s", ent->s);
29792f6c72eSMasami Hiramatsu 	if (ret < 0)
29892f6c72eSMasami Hiramatsu 		goto error;
29992f6c72eSMasami Hiramatsu 
30092f6c72eSMasami Hiramatsu 	p = strchr(buf + 2, ':');
30192f6c72eSMasami Hiramatsu 	if (!p) {
30292f6c72eSMasami Hiramatsu 		pr_debug("Internal error: %s should have ':' but not.\n",
30392f6c72eSMasami Hiramatsu 			 ent->s);
30492f6c72eSMasami Hiramatsu 		ret = -ENOTSUP;
30592f6c72eSMasami Hiramatsu 		goto error;
30692f6c72eSMasami Hiramatsu 	}
30792f6c72eSMasami Hiramatsu 	*p = '/';
30892f6c72eSMasami Hiramatsu 
30992f6c72eSMasami Hiramatsu 	pr_debug("Writing event: %s\n", buf);
31092f6c72eSMasami Hiramatsu 	ret = write(fd, buf, strlen(buf));
31192f6c72eSMasami Hiramatsu 	if (ret < 0) {
31292f6c72eSMasami Hiramatsu 		ret = -errno;
31392f6c72eSMasami Hiramatsu 		goto error;
31492f6c72eSMasami Hiramatsu 	}
31592f6c72eSMasami Hiramatsu 
31692f6c72eSMasami Hiramatsu 	return 0;
31792f6c72eSMasami Hiramatsu error:
31892f6c72eSMasami Hiramatsu 	pr_warning("Failed to delete event: %s\n",
319c8b5f2c9SArnaldo Carvalho de Melo 		   str_error_r(-ret, buf, sizeof(buf)));
32092f6c72eSMasami Hiramatsu 	return ret;
32192f6c72eSMasami Hiramatsu }
32292f6c72eSMasami Hiramatsu 
probe_file__get_events(int fd,struct strfilter * filter,struct strlist * plist)323e607f142SNamhyung Kim int probe_file__get_events(int fd, struct strfilter *filter,
324e7895e42SNamhyung Kim 			   struct strlist *plist)
32592f6c72eSMasami Hiramatsu {
32692f6c72eSMasami Hiramatsu 	struct strlist *namelist;
32792f6c72eSMasami Hiramatsu 	struct str_node *ent;
32892f6c72eSMasami Hiramatsu 	const char *p;
32992f6c72eSMasami Hiramatsu 	int ret = -ENOENT;
33092f6c72eSMasami Hiramatsu 
331421fd084SWang Nan 	if (!plist)
332421fd084SWang Nan 		return -EINVAL;
333421fd084SWang Nan 
33492f6c72eSMasami Hiramatsu 	namelist = __probe_file__get_namelist(fd, true);
33592f6c72eSMasami Hiramatsu 	if (!namelist)
33692f6c72eSMasami Hiramatsu 		return -ENOENT;
33792f6c72eSMasami Hiramatsu 
338602a1f4dSArnaldo Carvalho de Melo 	strlist__for_each_entry(ent, namelist) {
33992f6c72eSMasami Hiramatsu 		p = strchr(ent->s, ':');
34092f6c72eSMasami Hiramatsu 		if ((p && strfilter__compare(filter, p + 1)) ||
34192f6c72eSMasami Hiramatsu 		    strfilter__compare(filter, ent->s)) {
342bd862b1dSHe Zhe 			ret = strlist__add(plist, ent->s);
343bd862b1dSHe Zhe 			if (ret == -ENOMEM) {
344bd862b1dSHe Zhe 				pr_err("strlist__add failed with -ENOMEM\n");
345bd862b1dSHe Zhe 				goto out;
346bd862b1dSHe Zhe 			}
347e7895e42SNamhyung Kim 			ret = 0;
348e7895e42SNamhyung Kim 		}
349e7895e42SNamhyung Kim 	}
350bd862b1dSHe Zhe out:
351e7895e42SNamhyung Kim 	strlist__delete(namelist);
352e7895e42SNamhyung Kim 
353e7895e42SNamhyung Kim 	return ret;
354e7895e42SNamhyung Kim }
355e7895e42SNamhyung Kim 
probe_file__del_strlist(int fd,struct strlist * namelist)356e607f142SNamhyung Kim int probe_file__del_strlist(int fd, struct strlist *namelist)
357e7895e42SNamhyung Kim {
358e7895e42SNamhyung Kim 	int ret = 0;
359e7895e42SNamhyung Kim 	struct str_node *ent;
360e7895e42SNamhyung Kim 
361602a1f4dSArnaldo Carvalho de Melo 	strlist__for_each_entry(ent, namelist) {
36292f6c72eSMasami Hiramatsu 		ret = __del_trace_probe_event(fd, ent);
36392f6c72eSMasami Hiramatsu 		if (ret < 0)
36492f6c72eSMasami Hiramatsu 			break;
36592f6c72eSMasami Hiramatsu 	}
366e7895e42SNamhyung Kim 	return ret;
36792f6c72eSMasami Hiramatsu }
368e7895e42SNamhyung Kim 
probe_file__del_events(int fd,struct strfilter * filter)369e7895e42SNamhyung Kim int probe_file__del_events(int fd, struct strfilter *filter)
370e7895e42SNamhyung Kim {
371e7895e42SNamhyung Kim 	struct strlist *namelist;
372e7895e42SNamhyung Kim 	int ret;
373e7895e42SNamhyung Kim 
374e7895e42SNamhyung Kim 	namelist = strlist__new(NULL, NULL);
375e7895e42SNamhyung Kim 	if (!namelist)
376e7895e42SNamhyung Kim 		return -ENOMEM;
377e7895e42SNamhyung Kim 
378e7895e42SNamhyung Kim 	ret = probe_file__get_events(fd, filter, namelist);
379e7895e42SNamhyung Kim 	if (ret < 0)
380*e0fa7ab4SRiccardo Mancini 		goto out;
381e7895e42SNamhyung Kim 
382e7895e42SNamhyung Kim 	ret = probe_file__del_strlist(fd, namelist);
383*e0fa7ab4SRiccardo Mancini out:
38492f6c72eSMasami Hiramatsu 	strlist__delete(namelist);
38592f6c72eSMasami Hiramatsu 	return ret;
38692f6c72eSMasami Hiramatsu }
387dd975497SMasami Hiramatsu 
388dd975497SMasami Hiramatsu /* Caller must ensure to remove this entry from list */
probe_cache_entry__delete(struct probe_cache_entry * entry)389dd975497SMasami Hiramatsu static void probe_cache_entry__delete(struct probe_cache_entry *entry)
390dd975497SMasami Hiramatsu {
391dd975497SMasami Hiramatsu 	if (entry) {
392dd975497SMasami Hiramatsu 		BUG_ON(!list_empty(&entry->node));
393dd975497SMasami Hiramatsu 
394dd975497SMasami Hiramatsu 		strlist__delete(entry->tevlist);
395dd975497SMasami Hiramatsu 		clear_perf_probe_event(&entry->pev);
396dd975497SMasami Hiramatsu 		zfree(&entry->spev);
397dd975497SMasami Hiramatsu 		free(entry);
398dd975497SMasami Hiramatsu 	}
399dd975497SMasami Hiramatsu }
400dd975497SMasami Hiramatsu 
401dd975497SMasami Hiramatsu static struct probe_cache_entry *
probe_cache_entry__new(struct perf_probe_event * pev)402dd975497SMasami Hiramatsu probe_cache_entry__new(struct perf_probe_event *pev)
403dd975497SMasami Hiramatsu {
404dd975497SMasami Hiramatsu 	struct probe_cache_entry *entry = zalloc(sizeof(*entry));
405dd975497SMasami Hiramatsu 
406dd975497SMasami Hiramatsu 	if (entry) {
407dd975497SMasami Hiramatsu 		INIT_LIST_HEAD(&entry->node);
408dd975497SMasami Hiramatsu 		entry->tevlist = strlist__new(NULL, NULL);
409dd975497SMasami Hiramatsu 		if (!entry->tevlist)
410dd975497SMasami Hiramatsu 			zfree(&entry);
411dd975497SMasami Hiramatsu 		else if (pev) {
412dd975497SMasami Hiramatsu 			entry->spev = synthesize_perf_probe_command(pev);
413dd975497SMasami Hiramatsu 			if (!entry->spev ||
414dd975497SMasami Hiramatsu 			    perf_probe_event__copy(&entry->pev, pev) < 0) {
415dd975497SMasami Hiramatsu 				probe_cache_entry__delete(entry);
416dd975497SMasami Hiramatsu 				return NULL;
417dd975497SMasami Hiramatsu 			}
418dd975497SMasami Hiramatsu 		}
419dd975497SMasami Hiramatsu 	}
420dd975497SMasami Hiramatsu 
421dd975497SMasami Hiramatsu 	return entry;
422dd975497SMasami Hiramatsu }
423dd975497SMasami Hiramatsu 
probe_cache_entry__get_event(struct probe_cache_entry * entry,struct probe_trace_event ** tevs)42442bba263SMasami Hiramatsu int probe_cache_entry__get_event(struct probe_cache_entry *entry,
42542bba263SMasami Hiramatsu 				 struct probe_trace_event **tevs)
42642bba263SMasami Hiramatsu {
42742bba263SMasami Hiramatsu 	struct probe_trace_event *tev;
42842bba263SMasami Hiramatsu 	struct str_node *node;
42942bba263SMasami Hiramatsu 	int ret, i;
43042bba263SMasami Hiramatsu 
43142bba263SMasami Hiramatsu 	ret = strlist__nr_entries(entry->tevlist);
43242bba263SMasami Hiramatsu 	if (ret > probe_conf.max_probes)
43342bba263SMasami Hiramatsu 		return -E2BIG;
43442bba263SMasami Hiramatsu 
43542bba263SMasami Hiramatsu 	*tevs = zalloc(ret * sizeof(*tev));
43642bba263SMasami Hiramatsu 	if (!*tevs)
43742bba263SMasami Hiramatsu 		return -ENOMEM;
43842bba263SMasami Hiramatsu 
43942bba263SMasami Hiramatsu 	i = 0;
44042bba263SMasami Hiramatsu 	strlist__for_each_entry(node, entry->tevlist) {
44142bba263SMasami Hiramatsu 		tev = &(*tevs)[i++];
44242bba263SMasami Hiramatsu 		ret = parse_probe_trace_command(node->s, tev);
44342bba263SMasami Hiramatsu 		if (ret < 0)
44442bba263SMasami Hiramatsu 			break;
44542bba263SMasami Hiramatsu 	}
44642bba263SMasami Hiramatsu 	return i;
44742bba263SMasami Hiramatsu }
44842bba263SMasami Hiramatsu 
44942bba263SMasami Hiramatsu /* For the kernel probe caches, pass target = NULL or DSO__NAME_KALLSYMS */
probe_cache__open(struct probe_cache * pcache,const char * target,struct nsinfo * nsi)450f045b8c4SKrister Johansen static int probe_cache__open(struct probe_cache *pcache, const char *target,
451f045b8c4SKrister Johansen 			     struct nsinfo *nsi)
452dd975497SMasami Hiramatsu {
453dd975497SMasami Hiramatsu 	char cpath[PATH_MAX];
454dd975497SMasami Hiramatsu 	char sbuildid[SBUILD_ID_SIZE];
4551f3736c9SMasami Hiramatsu 	char *dir_name = NULL;
45642bba263SMasami Hiramatsu 	bool is_kallsyms = false;
457dd975497SMasami Hiramatsu 	int ret, fd;
458f045b8c4SKrister Johansen 	struct nscookie nsc;
459dd975497SMasami Hiramatsu 
4601f3736c9SMasami Hiramatsu 	if (target && build_id_cache__cached(target)) {
4611f3736c9SMasami Hiramatsu 		/* This is a cached buildid */
462bef0b897SArnaldo Carvalho de Melo 		strlcpy(sbuildid, target, SBUILD_ID_SIZE);
4631f3736c9SMasami Hiramatsu 		dir_name = build_id_cache__linkname(sbuildid, NULL, 0);
4641f3736c9SMasami Hiramatsu 		goto found;
4651f3736c9SMasami Hiramatsu 	}
4661f3736c9SMasami Hiramatsu 
46742bba263SMasami Hiramatsu 	if (!target || !strcmp(target, DSO__NAME_KALLSYMS)) {
468dd975497SMasami Hiramatsu 		target = DSO__NAME_KALLSYMS;
46942bba263SMasami Hiramatsu 		is_kallsyms = true;
470dd975497SMasami Hiramatsu 		ret = sysfs__sprintf_build_id("/", sbuildid);
471f045b8c4SKrister Johansen 	} else {
472f045b8c4SKrister Johansen 		nsinfo__mountns_enter(nsi, &nsc);
47342bba263SMasami Hiramatsu 		ret = filename__sprintf_build_id(target, sbuildid);
474f045b8c4SKrister Johansen 		nsinfo__mountns_exit(&nsc);
475f045b8c4SKrister Johansen 	}
47642bba263SMasami Hiramatsu 
477dd975497SMasami Hiramatsu 	if (ret < 0) {
478dd975497SMasami Hiramatsu 		pr_debug("Failed to get build-id from %s.\n", target);
479dd975497SMasami Hiramatsu 		return ret;
480dd975497SMasami Hiramatsu 	}
481dd975497SMasami Hiramatsu 
482dd975497SMasami Hiramatsu 	/* If we have no buildid cache, make it */
483dd975497SMasami Hiramatsu 	if (!build_id_cache__cached(sbuildid)) {
484f045b8c4SKrister Johansen 		ret = build_id_cache__add_s(sbuildid, target, nsi,
485dd975497SMasami Hiramatsu 					    is_kallsyms, NULL);
486dd975497SMasami Hiramatsu 		if (ret < 0) {
487dd975497SMasami Hiramatsu 			pr_debug("Failed to add build-id cache: %s\n", target);
488dd975497SMasami Hiramatsu 			return ret;
489dd975497SMasami Hiramatsu 		}
490dd975497SMasami Hiramatsu 	}
491dd975497SMasami Hiramatsu 
492f045b8c4SKrister Johansen 	dir_name = build_id_cache__cachedir(sbuildid, target, nsi, is_kallsyms,
493dd975497SMasami Hiramatsu 					    false);
4941f3736c9SMasami Hiramatsu found:
4951f3736c9SMasami Hiramatsu 	if (!dir_name) {
4961f3736c9SMasami Hiramatsu 		pr_debug("Failed to get cache from %s\n", target);
497dd975497SMasami Hiramatsu 		return -ENOMEM;
4981f3736c9SMasami Hiramatsu 	}
499dd975497SMasami Hiramatsu 
500dd975497SMasami Hiramatsu 	snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
501dd975497SMasami Hiramatsu 	fd = open(cpath, O_CREAT | O_RDWR, 0644);
502dd975497SMasami Hiramatsu 	if (fd < 0)
503dd975497SMasami Hiramatsu 		pr_debug("Failed to open cache(%d): %s\n", fd, cpath);
504dd975497SMasami Hiramatsu 	free(dir_name);
505dd975497SMasami Hiramatsu 	pcache->fd = fd;
506dd975497SMasami Hiramatsu 
507dd975497SMasami Hiramatsu 	return fd;
508dd975497SMasami Hiramatsu }
509dd975497SMasami Hiramatsu 
probe_cache__load(struct probe_cache * pcache)510dd975497SMasami Hiramatsu static int probe_cache__load(struct probe_cache *pcache)
511dd975497SMasami Hiramatsu {
512dd975497SMasami Hiramatsu 	struct probe_cache_entry *entry = NULL;
513dd975497SMasami Hiramatsu 	char buf[MAX_CMDLEN], *p;
5140325862dSColin Ian King 	int ret = 0, fddup;
515dd975497SMasami Hiramatsu 	FILE *fp;
516dd975497SMasami Hiramatsu 
5170325862dSColin Ian King 	fddup = dup(pcache->fd);
5180325862dSColin Ian King 	if (fddup < 0)
5190325862dSColin Ian King 		return -errno;
5200325862dSColin Ian King 	fp = fdopen(fddup, "r");
52160ebc159SArnaldo Carvalho de Melo 	if (!fp) {
52260ebc159SArnaldo Carvalho de Melo 		close(fddup);
523dd975497SMasami Hiramatsu 		return -EINVAL;
52460ebc159SArnaldo Carvalho de Melo 	}
525dd975497SMasami Hiramatsu 
526dd975497SMasami Hiramatsu 	while (!feof(fp)) {
527dd975497SMasami Hiramatsu 		if (!fgets(buf, MAX_CMDLEN, fp))
528dd975497SMasami Hiramatsu 			break;
529dd975497SMasami Hiramatsu 		p = strchr(buf, '\n');
530dd975497SMasami Hiramatsu 		if (p)
531dd975497SMasami Hiramatsu 			*p = '\0';
5326430a94eSMasami Hiramatsu 		/* #perf_probe_event or %sdt_event */
5336430a94eSMasami Hiramatsu 		if (buf[0] == '#' || buf[0] == '%') {
534dd975497SMasami Hiramatsu 			entry = probe_cache_entry__new(NULL);
535dd975497SMasami Hiramatsu 			if (!entry) {
536dd975497SMasami Hiramatsu 				ret = -ENOMEM;
537dd975497SMasami Hiramatsu 				goto out;
538dd975497SMasami Hiramatsu 			}
5396430a94eSMasami Hiramatsu 			if (buf[0] == '%')
5406430a94eSMasami Hiramatsu 				entry->sdt = true;
541dd975497SMasami Hiramatsu 			entry->spev = strdup(buf + 1);
542dd975497SMasami Hiramatsu 			if (entry->spev)
543dd975497SMasami Hiramatsu 				ret = parse_perf_probe_command(buf + 1,
544dd975497SMasami Hiramatsu 								&entry->pev);
545dd975497SMasami Hiramatsu 			else
546dd975497SMasami Hiramatsu 				ret = -ENOMEM;
547dd975497SMasami Hiramatsu 			if (ret < 0) {
548dd975497SMasami Hiramatsu 				probe_cache_entry__delete(entry);
549dd975497SMasami Hiramatsu 				goto out;
550dd975497SMasami Hiramatsu 			}
551dd975497SMasami Hiramatsu 			list_add_tail(&entry->node, &pcache->entries);
552dd975497SMasami Hiramatsu 		} else {	/* trace_probe_event */
553dd975497SMasami Hiramatsu 			if (!entry) {
554dd975497SMasami Hiramatsu 				ret = -EINVAL;
555dd975497SMasami Hiramatsu 				goto out;
556dd975497SMasami Hiramatsu 			}
557bd862b1dSHe Zhe 			ret = strlist__add(entry->tevlist, buf);
558bd862b1dSHe Zhe 			if (ret == -ENOMEM) {
559bd862b1dSHe Zhe 				pr_err("strlist__add failed with -ENOMEM\n");
560bd862b1dSHe Zhe 				goto out;
561bd862b1dSHe Zhe 			}
562dd975497SMasami Hiramatsu 		}
563dd975497SMasami Hiramatsu 	}
564dd975497SMasami Hiramatsu out:
565dd975497SMasami Hiramatsu 	fclose(fp);
566dd975497SMasami Hiramatsu 	return ret;
567dd975497SMasami Hiramatsu }
568dd975497SMasami Hiramatsu 
probe_cache__alloc(void)569dd975497SMasami Hiramatsu static struct probe_cache *probe_cache__alloc(void)
570dd975497SMasami Hiramatsu {
571dd975497SMasami Hiramatsu 	struct probe_cache *pcache = zalloc(sizeof(*pcache));
572dd975497SMasami Hiramatsu 
573dd975497SMasami Hiramatsu 	if (pcache) {
574dd975497SMasami Hiramatsu 		INIT_LIST_HEAD(&pcache->entries);
575dd975497SMasami Hiramatsu 		pcache->fd = -EINVAL;
576dd975497SMasami Hiramatsu 	}
577dd975497SMasami Hiramatsu 	return pcache;
578dd975497SMasami Hiramatsu }
579dd975497SMasami Hiramatsu 
probe_cache__purge(struct probe_cache * pcache)580dd975497SMasami Hiramatsu void probe_cache__purge(struct probe_cache *pcache)
581dd975497SMasami Hiramatsu {
582dd975497SMasami Hiramatsu 	struct probe_cache_entry *entry, *n;
583dd975497SMasami Hiramatsu 
584dd975497SMasami Hiramatsu 	list_for_each_entry_safe(entry, n, &pcache->entries, node) {
585dd975497SMasami Hiramatsu 		list_del_init(&entry->node);
586dd975497SMasami Hiramatsu 		probe_cache_entry__delete(entry);
587dd975497SMasami Hiramatsu 	}
588dd975497SMasami Hiramatsu }
589dd975497SMasami Hiramatsu 
probe_cache__delete(struct probe_cache * pcache)590dd975497SMasami Hiramatsu void probe_cache__delete(struct probe_cache *pcache)
591dd975497SMasami Hiramatsu {
592dd975497SMasami Hiramatsu 	if (!pcache)
593dd975497SMasami Hiramatsu 		return;
594dd975497SMasami Hiramatsu 
595dd975497SMasami Hiramatsu 	probe_cache__purge(pcache);
596dd975497SMasami Hiramatsu 	if (pcache->fd > 0)
597dd975497SMasami Hiramatsu 		close(pcache->fd);
598dd975497SMasami Hiramatsu 	free(pcache);
599dd975497SMasami Hiramatsu }
600dd975497SMasami Hiramatsu 
probe_cache__new(const char * target,struct nsinfo * nsi)601f045b8c4SKrister Johansen struct probe_cache *probe_cache__new(const char *target, struct nsinfo *nsi)
602dd975497SMasami Hiramatsu {
603dd975497SMasami Hiramatsu 	struct probe_cache *pcache = probe_cache__alloc();
604dd975497SMasami Hiramatsu 	int ret;
605dd975497SMasami Hiramatsu 
606dd975497SMasami Hiramatsu 	if (!pcache)
607dd975497SMasami Hiramatsu 		return NULL;
608dd975497SMasami Hiramatsu 
609f045b8c4SKrister Johansen 	ret = probe_cache__open(pcache, target, nsi);
610dd975497SMasami Hiramatsu 	if (ret < 0) {
611dd975497SMasami Hiramatsu 		pr_debug("Cache open error: %d\n", ret);
612dd975497SMasami Hiramatsu 		goto out_err;
613dd975497SMasami Hiramatsu 	}
614dd975497SMasami Hiramatsu 
615dd975497SMasami Hiramatsu 	ret = probe_cache__load(pcache);
616dd975497SMasami Hiramatsu 	if (ret < 0) {
617dd975497SMasami Hiramatsu 		pr_debug("Cache read error: %d\n", ret);
618dd975497SMasami Hiramatsu 		goto out_err;
619dd975497SMasami Hiramatsu 	}
620dd975497SMasami Hiramatsu 
621dd975497SMasami Hiramatsu 	return pcache;
622dd975497SMasami Hiramatsu 
623dd975497SMasami Hiramatsu out_err:
624dd975497SMasami Hiramatsu 	probe_cache__delete(pcache);
625dd975497SMasami Hiramatsu 	return NULL;
626dd975497SMasami Hiramatsu }
627dd975497SMasami Hiramatsu 
streql(const char * a,const char * b)628dd975497SMasami Hiramatsu static bool streql(const char *a, const char *b)
629dd975497SMasami Hiramatsu {
630dd975497SMasami Hiramatsu 	if (a == b)
631dd975497SMasami Hiramatsu 		return true;
632dd975497SMasami Hiramatsu 
633dd975497SMasami Hiramatsu 	if (!a || !b)
634dd975497SMasami Hiramatsu 		return false;
635dd975497SMasami Hiramatsu 
636dd975497SMasami Hiramatsu 	return !strcmp(a, b);
637dd975497SMasami Hiramatsu }
638dd975497SMasami Hiramatsu 
639bc062230SMasami Hiramatsu struct probe_cache_entry *
probe_cache__find(struct probe_cache * pcache,struct perf_probe_event * pev)640dd975497SMasami Hiramatsu probe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
641dd975497SMasami Hiramatsu {
642dd975497SMasami Hiramatsu 	struct probe_cache_entry *entry = NULL;
643dd975497SMasami Hiramatsu 	char *cmd = synthesize_perf_probe_command(pev);
644dd975497SMasami Hiramatsu 
645dd975497SMasami Hiramatsu 	if (!cmd)
646dd975497SMasami Hiramatsu 		return NULL;
647dd975497SMasami Hiramatsu 
64805bf2c8aSMasami Hiramatsu 	for_each_probe_cache_entry(entry, pcache) {
64936a009feSMasami Hiramatsu 		if (pev->sdt) {
65036a009feSMasami Hiramatsu 			if (entry->pev.event &&
65136a009feSMasami Hiramatsu 			    streql(entry->pev.event, pev->event) &&
65236a009feSMasami Hiramatsu 			    (!pev->group ||
65336a009feSMasami Hiramatsu 			     streql(entry->pev.group, pev->group)))
65436a009feSMasami Hiramatsu 				goto found;
65536a009feSMasami Hiramatsu 
65636a009feSMasami Hiramatsu 			continue;
65736a009feSMasami Hiramatsu 		}
658dd975497SMasami Hiramatsu 		/* Hit if same event name or same command-string */
659dd975497SMasami Hiramatsu 		if ((pev->event &&
660dd975497SMasami Hiramatsu 		     (streql(entry->pev.group, pev->group) &&
661dd975497SMasami Hiramatsu 		      streql(entry->pev.event, pev->event))) ||
662dd975497SMasami Hiramatsu 		    (!strcmp(entry->spev, cmd)))
663dd975497SMasami Hiramatsu 			goto found;
664dd975497SMasami Hiramatsu 	}
665dd975497SMasami Hiramatsu 	entry = NULL;
666dd975497SMasami Hiramatsu 
667dd975497SMasami Hiramatsu found:
668dd975497SMasami Hiramatsu 	free(cmd);
669dd975497SMasami Hiramatsu 	return entry;
670dd975497SMasami Hiramatsu }
671dd975497SMasami Hiramatsu 
672bc062230SMasami Hiramatsu struct probe_cache_entry *
probe_cache__find_by_name(struct probe_cache * pcache,const char * group,const char * event)673bc062230SMasami Hiramatsu probe_cache__find_by_name(struct probe_cache *pcache,
674bc062230SMasami Hiramatsu 			  const char *group, const char *event)
675bc062230SMasami Hiramatsu {
676bc062230SMasami Hiramatsu 	struct probe_cache_entry *entry = NULL;
677bc062230SMasami Hiramatsu 
67805bf2c8aSMasami Hiramatsu 	for_each_probe_cache_entry(entry, pcache) {
679bc062230SMasami Hiramatsu 		/* Hit if same event name or same command-string */
680bc062230SMasami Hiramatsu 		if (streql(entry->pev.group, group) &&
681bc062230SMasami Hiramatsu 		    streql(entry->pev.event, event))
682bc062230SMasami Hiramatsu 			goto found;
683bc062230SMasami Hiramatsu 	}
684bc062230SMasami Hiramatsu 	entry = NULL;
685bc062230SMasami Hiramatsu 
686bc062230SMasami Hiramatsu found:
687bc062230SMasami Hiramatsu 	return entry;
688bc062230SMasami Hiramatsu }
689bc062230SMasami Hiramatsu 
probe_cache__add_entry(struct probe_cache * pcache,struct perf_probe_event * pev,struct probe_trace_event * tevs,int ntevs)690dd975497SMasami Hiramatsu int probe_cache__add_entry(struct probe_cache *pcache,
691dd975497SMasami Hiramatsu 			   struct perf_probe_event *pev,
692dd975497SMasami Hiramatsu 			   struct probe_trace_event *tevs, int ntevs)
693dd975497SMasami Hiramatsu {
694dd975497SMasami Hiramatsu 	struct probe_cache_entry *entry = NULL;
695dd975497SMasami Hiramatsu 	char *command;
696dd975497SMasami Hiramatsu 	int i, ret = 0;
697dd975497SMasami Hiramatsu 
698dd975497SMasami Hiramatsu 	if (!pcache || !pev || !tevs || ntevs <= 0) {
699dd975497SMasami Hiramatsu 		ret = -EINVAL;
700dd975497SMasami Hiramatsu 		goto out_err;
701dd975497SMasami Hiramatsu 	}
702dd975497SMasami Hiramatsu 
703dd975497SMasami Hiramatsu 	/* Remove old cache entry */
704dd975497SMasami Hiramatsu 	entry = probe_cache__find(pcache, pev);
705dd975497SMasami Hiramatsu 	if (entry) {
706dd975497SMasami Hiramatsu 		list_del_init(&entry->node);
707dd975497SMasami Hiramatsu 		probe_cache_entry__delete(entry);
708dd975497SMasami Hiramatsu 	}
709dd975497SMasami Hiramatsu 
710dd975497SMasami Hiramatsu 	ret = -ENOMEM;
711dd975497SMasami Hiramatsu 	entry = probe_cache_entry__new(pev);
712dd975497SMasami Hiramatsu 	if (!entry)
713dd975497SMasami Hiramatsu 		goto out_err;
714dd975497SMasami Hiramatsu 
715dd975497SMasami Hiramatsu 	for (i = 0; i < ntevs; i++) {
716dd975497SMasami Hiramatsu 		if (!tevs[i].point.symbol)
717dd975497SMasami Hiramatsu 			continue;
718dd975497SMasami Hiramatsu 
719dd975497SMasami Hiramatsu 		command = synthesize_probe_trace_command(&tevs[i]);
720dd975497SMasami Hiramatsu 		if (!command)
721dd975497SMasami Hiramatsu 			goto out_err;
722bd862b1dSHe Zhe 		ret = strlist__add(entry->tevlist, command);
723bd862b1dSHe Zhe 		if (ret == -ENOMEM) {
724bd862b1dSHe Zhe 			pr_err("strlist__add failed with -ENOMEM\n");
725bd862b1dSHe Zhe 			goto out_err;
726bd862b1dSHe Zhe 		}
727bd862b1dSHe Zhe 
728dd975497SMasami Hiramatsu 		free(command);
729dd975497SMasami Hiramatsu 	}
730dd975497SMasami Hiramatsu 	list_add_tail(&entry->node, &pcache->entries);
731dd975497SMasami Hiramatsu 	pr_debug("Added probe cache: %d\n", ntevs);
732dd975497SMasami Hiramatsu 	return 0;
733dd975497SMasami Hiramatsu 
734dd975497SMasami Hiramatsu out_err:
735dd975497SMasami Hiramatsu 	pr_debug("Failed to add probe caches\n");
736dd975497SMasami Hiramatsu 	probe_cache_entry__delete(entry);
737dd975497SMasami Hiramatsu 	return ret;
738dd975497SMasami Hiramatsu }
739dd975497SMasami Hiramatsu 
7401c1a3a47SArnaldo Carvalho de Melo #ifdef HAVE_GELF_GETNOTE_SUPPORT
sdt_note__get_addr(struct sdt_note * note)7416430a94eSMasami Hiramatsu static unsigned long long sdt_note__get_addr(struct sdt_note *note)
7426430a94eSMasami Hiramatsu {
7435a5e3d3cSRavi Bangoria 	return note->bit32 ?
7445a5e3d3cSRavi Bangoria 		(unsigned long long)note->addr.a32[SDT_NOTE_IDX_LOC] :
7455a5e3d3cSRavi Bangoria 		(unsigned long long)note->addr.a64[SDT_NOTE_IDX_LOC];
7465a5e3d3cSRavi Bangoria }
7475a5e3d3cSRavi Bangoria 
sdt_note__get_ref_ctr_offset(struct sdt_note * note)7485a5e3d3cSRavi Bangoria static unsigned long long sdt_note__get_ref_ctr_offset(struct sdt_note *note)
7495a5e3d3cSRavi Bangoria {
7505a5e3d3cSRavi Bangoria 	return note->bit32 ?
7515a5e3d3cSRavi Bangoria 		(unsigned long long)note->addr.a32[SDT_NOTE_IDX_REFCTR] :
7525a5e3d3cSRavi Bangoria 		(unsigned long long)note->addr.a64[SDT_NOTE_IDX_REFCTR];
7536430a94eSMasami Hiramatsu }
7546430a94eSMasami Hiramatsu 
7553b1f8311SAlexis Berlemont static const char * const type_to_suffix[] = {
7563b1f8311SAlexis Berlemont 	":s64", "", "", "", ":s32", "", ":s16", ":s8",
7573b1f8311SAlexis Berlemont 	"", ":u8", ":u16", "", ":u32", "", "", "", ":u64"
7583b1f8311SAlexis Berlemont };
7593b1f8311SAlexis Berlemont 
760d451a205SRavi Bangoria /*
761d451a205SRavi Bangoria  * Isolate the string number and convert it into a decimal value;
762d451a205SRavi Bangoria  * this will be an index to get suffix of the uprobe name (defining
763d451a205SRavi Bangoria  * the type)
764d451a205SRavi Bangoria  */
sdt_arg_parse_size(char * n_ptr,const char ** suffix)765d451a205SRavi Bangoria static int sdt_arg_parse_size(char *n_ptr, const char **suffix)
766d451a205SRavi Bangoria {
767d451a205SRavi Bangoria 	long type_idx;
768d451a205SRavi Bangoria 
769d451a205SRavi Bangoria 	type_idx = strtol(n_ptr, NULL, 10);
770d451a205SRavi Bangoria 	if (type_idx < -8 || type_idx > 8) {
771d451a205SRavi Bangoria 		pr_debug4("Failed to get a valid sdt type\n");
772d451a205SRavi Bangoria 		return -1;
773d451a205SRavi Bangoria 	}
774d451a205SRavi Bangoria 
775d451a205SRavi Bangoria 	*suffix = type_to_suffix[type_idx + 8];
776d451a205SRavi Bangoria 	return 0;
777d451a205SRavi Bangoria }
778d451a205SRavi Bangoria 
synthesize_sdt_probe_arg(struct strbuf * buf,int i,const char * arg)7793b1f8311SAlexis Berlemont static int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg)
7803b1f8311SAlexis Berlemont {
781d451a205SRavi Bangoria 	char *op, *desc = strdup(arg), *new_op = NULL;
782d451a205SRavi Bangoria 	const char *suffix = "";
7833b1f8311SAlexis Berlemont 	int ret = -1;
7843b1f8311SAlexis Berlemont 
7853b1f8311SAlexis Berlemont 	if (desc == NULL) {
7863b1f8311SAlexis Berlemont 		pr_debug4("Allocation error\n");
7873b1f8311SAlexis Berlemont 		return ret;
7883b1f8311SAlexis Berlemont 	}
7893b1f8311SAlexis Berlemont 
7903b1f8311SAlexis Berlemont 	/*
791d451a205SRavi Bangoria 	 * Argument is in N@OP format. N is size of the argument and OP is
792d451a205SRavi Bangoria 	 * the actual assembly operand. N can be omitted; in that case
793d451a205SRavi Bangoria 	 * argument is just OP(without @).
7943b1f8311SAlexis Berlemont 	 */
795d451a205SRavi Bangoria 	op = strchr(desc, '@');
796d451a205SRavi Bangoria 	if (op) {
797d451a205SRavi Bangoria 		op[0] = '\0';
798d451a205SRavi Bangoria 		op++;
799d451a205SRavi Bangoria 
800d451a205SRavi Bangoria 		if (sdt_arg_parse_size(desc, &suffix))
8013b1f8311SAlexis Berlemont 			goto error;
802d451a205SRavi Bangoria 	} else {
803d451a205SRavi Bangoria 		op = desc;
8043b1f8311SAlexis Berlemont 	}
8053b1f8311SAlexis Berlemont 
806d451a205SRavi Bangoria 	ret = arch_sdt_arg_parse_op(op, &new_op);
8073b1f8311SAlexis Berlemont 
8083b1f8311SAlexis Berlemont 	if (ret < 0)
8093b1f8311SAlexis Berlemont 		goto error;
8103b1f8311SAlexis Berlemont 
811d451a205SRavi Bangoria 	if (ret == SDT_ARG_VALID) {
812d451a205SRavi Bangoria 		ret = strbuf_addf(buf, " arg%d=%s%s", i + 1, new_op, suffix);
813d451a205SRavi Bangoria 		if (ret < 0)
814d451a205SRavi Bangoria 			goto error;
8153b1f8311SAlexis Berlemont 	}
8163b1f8311SAlexis Berlemont 
8173b1f8311SAlexis Berlemont 	ret = 0;
8183b1f8311SAlexis Berlemont error:
8193b1f8311SAlexis Berlemont 	free(desc);
820d451a205SRavi Bangoria 	free(new_op);
8213b1f8311SAlexis Berlemont 	return ret;
8223b1f8311SAlexis Berlemont }
8233b1f8311SAlexis Berlemont 
synthesize_sdt_probe_command(struct sdt_note * note,const char * pathname,const char * sdtgrp)8243b1f8311SAlexis Berlemont static char *synthesize_sdt_probe_command(struct sdt_note *note,
8253b1f8311SAlexis Berlemont 					const char *pathname,
8263b1f8311SAlexis Berlemont 					const char *sdtgrp)
8273b1f8311SAlexis Berlemont {
8283b1f8311SAlexis Berlemont 	struct strbuf buf;
8295149303fSArnaldo Carvalho de Melo 	char *ret = NULL;
8305a5e3d3cSRavi Bangoria 	int i, args_count, err;
8315a5e3d3cSRavi Bangoria 	unsigned long long ref_ctr_offset;
832f19b5872SLeo Yan 	char *arg;
833f19b5872SLeo Yan 	int arg_idx = 0;
8343b1f8311SAlexis Berlemont 
8353b1f8311SAlexis Berlemont 	if (strbuf_init(&buf, 32) < 0)
8363b1f8311SAlexis Berlemont 		return NULL;
8373b1f8311SAlexis Berlemont 
8385a5e3d3cSRavi Bangoria 	err = strbuf_addf(&buf, "p:%s/%s %s:0x%llx",
8393b1f8311SAlexis Berlemont 			sdtgrp, note->name, pathname,
8405a5e3d3cSRavi Bangoria 			sdt_note__get_addr(note));
8415a5e3d3cSRavi Bangoria 
8425a5e3d3cSRavi Bangoria 	ref_ctr_offset = sdt_note__get_ref_ctr_offset(note);
8435a5e3d3cSRavi Bangoria 	if (ref_ctr_offset && err >= 0)
8445a5e3d3cSRavi Bangoria 		err = strbuf_addf(&buf, "(0x%llx)", ref_ctr_offset);
8455a5e3d3cSRavi Bangoria 
8465a5e3d3cSRavi Bangoria 	if (err < 0)
8473b1f8311SAlexis Berlemont 		goto error;
8483b1f8311SAlexis Berlemont 
8493b1f8311SAlexis Berlemont 	if (!note->args)
8503b1f8311SAlexis Berlemont 		goto out;
8513b1f8311SAlexis Berlemont 
8523b1f8311SAlexis Berlemont 	if (note->args) {
8535149303fSArnaldo Carvalho de Melo 		char **args = argv_split(note->args, &args_count);
8545149303fSArnaldo Carvalho de Melo 
8555149303fSArnaldo Carvalho de Melo 		if (args == NULL)
8565149303fSArnaldo Carvalho de Melo 			goto error;
8573b1f8311SAlexis Berlemont 
858f19b5872SLeo Yan 		for (i = 0; i < args_count; ) {
859f19b5872SLeo Yan 			/*
860f19b5872SLeo Yan 			 * FIXUP: Arm64 ELF section '.note.stapsdt' uses string
861f19b5872SLeo Yan 			 * format "-4@[sp, NUM]" if a probe is to access data in
862f19b5872SLeo Yan 			 * the stack, e.g. below is an example for the SDT
863f19b5872SLeo Yan 			 * Arguments:
864f19b5872SLeo Yan 			 *
865f19b5872SLeo Yan 			 *   Arguments: -4@[sp, 12] -4@[sp, 8] -4@[sp, 4]
866f19b5872SLeo Yan 			 *
867f19b5872SLeo Yan 			 * Since the string introduces an extra space character
868f19b5872SLeo Yan 			 * in the middle of square brackets, the argument is
869f19b5872SLeo Yan 			 * divided into two items.  Fixup for this case, if an
870f19b5872SLeo Yan 			 * item contains sub string "[sp,", need to concatenate
871f19b5872SLeo Yan 			 * the two items.
872f19b5872SLeo Yan 			 */
873f19b5872SLeo Yan 			if (strstr(args[i], "[sp,") && (i+1) < args_count) {
874f19b5872SLeo Yan 				err = asprintf(&arg, "%s %s", args[i], args[i+1]);
875f19b5872SLeo Yan 				i += 2;
876f19b5872SLeo Yan 			} else {
877f19b5872SLeo Yan 				err = asprintf(&arg, "%s", args[i]);
878f19b5872SLeo Yan 				i += 1;
879f19b5872SLeo Yan 			}
880f19b5872SLeo Yan 
881f19b5872SLeo Yan 			/* Failed to allocate memory */
882f19b5872SLeo Yan 			if (err < 0) {
8835149303fSArnaldo Carvalho de Melo 				argv_free(args);
8843b1f8311SAlexis Berlemont 				goto error;
8853b1f8311SAlexis Berlemont 			}
886f19b5872SLeo Yan 
887f19b5872SLeo Yan 			if (synthesize_sdt_probe_arg(&buf, arg_idx, arg) < 0) {
888f19b5872SLeo Yan 				free(arg);
889f19b5872SLeo Yan 				argv_free(args);
890f19b5872SLeo Yan 				goto error;
891f19b5872SLeo Yan 			}
892f19b5872SLeo Yan 
893f19b5872SLeo Yan 			free(arg);
894f19b5872SLeo Yan 			arg_idx++;
8953b1f8311SAlexis Berlemont 		}
8963b1f8311SAlexis Berlemont 
8975149303fSArnaldo Carvalho de Melo 		argv_free(args);
8985149303fSArnaldo Carvalho de Melo 	}
8995149303fSArnaldo Carvalho de Melo 
9003b1f8311SAlexis Berlemont out:
9013b1f8311SAlexis Berlemont 	ret = strbuf_detach(&buf, NULL);
9023b1f8311SAlexis Berlemont error:
9033b1f8311SAlexis Berlemont 	strbuf_release(&buf);
9043b1f8311SAlexis Berlemont 	return ret;
9053b1f8311SAlexis Berlemont }
9063b1f8311SAlexis Berlemont 
probe_cache__scan_sdt(struct probe_cache * pcache,const char * pathname)9076430a94eSMasami Hiramatsu int probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
9086430a94eSMasami Hiramatsu {
9096430a94eSMasami Hiramatsu 	struct probe_cache_entry *entry = NULL;
9106430a94eSMasami Hiramatsu 	struct list_head sdtlist;
9116430a94eSMasami Hiramatsu 	struct sdt_note *note;
9126430a94eSMasami Hiramatsu 	char *buf;
9136430a94eSMasami Hiramatsu 	char sdtgrp[64];
9146430a94eSMasami Hiramatsu 	int ret;
9156430a94eSMasami Hiramatsu 
9166430a94eSMasami Hiramatsu 	INIT_LIST_HEAD(&sdtlist);
9176430a94eSMasami Hiramatsu 	ret = get_sdt_note_list(&sdtlist, pathname);
9186430a94eSMasami Hiramatsu 	if (ret < 0) {
919f9655200SAdrian Hunter 		pr_debug4("Failed to get sdt note: %d\n", ret);
9206430a94eSMasami Hiramatsu 		return ret;
9216430a94eSMasami Hiramatsu 	}
9226430a94eSMasami Hiramatsu 	list_for_each_entry(note, &sdtlist, note_list) {
9236430a94eSMasami Hiramatsu 		ret = snprintf(sdtgrp, 64, "sdt_%s", note->provider);
9246430a94eSMasami Hiramatsu 		if (ret < 0)
9256430a94eSMasami Hiramatsu 			break;
9266430a94eSMasami Hiramatsu 		/* Try to find same-name entry */
9276430a94eSMasami Hiramatsu 		entry = probe_cache__find_by_name(pcache, sdtgrp, note->name);
9286430a94eSMasami Hiramatsu 		if (!entry) {
9296430a94eSMasami Hiramatsu 			entry = probe_cache_entry__new(NULL);
9306430a94eSMasami Hiramatsu 			if (!entry) {
9316430a94eSMasami Hiramatsu 				ret = -ENOMEM;
9326430a94eSMasami Hiramatsu 				break;
9336430a94eSMasami Hiramatsu 			}
9346430a94eSMasami Hiramatsu 			entry->sdt = true;
9356430a94eSMasami Hiramatsu 			ret = asprintf(&entry->spev, "%s:%s=%s", sdtgrp,
9366430a94eSMasami Hiramatsu 					note->name, note->name);
9376430a94eSMasami Hiramatsu 			if (ret < 0)
9386430a94eSMasami Hiramatsu 				break;
9396430a94eSMasami Hiramatsu 			entry->pev.event = strdup(note->name);
9406430a94eSMasami Hiramatsu 			entry->pev.group = strdup(sdtgrp);
9416430a94eSMasami Hiramatsu 			list_add_tail(&entry->node, &pcache->entries);
9426430a94eSMasami Hiramatsu 		}
9433b1f8311SAlexis Berlemont 		buf = synthesize_sdt_probe_command(note, pathname, sdtgrp);
9443b1f8311SAlexis Berlemont 		if (!buf) {
9453b1f8311SAlexis Berlemont 			ret = -ENOMEM;
9466430a94eSMasami Hiramatsu 			break;
9473b1f8311SAlexis Berlemont 		}
9483b1f8311SAlexis Berlemont 
949bd862b1dSHe Zhe 		ret = strlist__add(entry->tevlist, buf);
950bd862b1dSHe Zhe 
9516430a94eSMasami Hiramatsu 		free(buf);
9526430a94eSMasami Hiramatsu 		entry = NULL;
953bd862b1dSHe Zhe 
954bd862b1dSHe Zhe 		if (ret == -ENOMEM) {
955bd862b1dSHe Zhe 			pr_err("strlist__add failed with -ENOMEM\n");
956bd862b1dSHe Zhe 			break;
957bd862b1dSHe Zhe 		}
9586430a94eSMasami Hiramatsu 	}
9596430a94eSMasami Hiramatsu 	if (entry) {
9606430a94eSMasami Hiramatsu 		list_del_init(&entry->node);
9616430a94eSMasami Hiramatsu 		probe_cache_entry__delete(entry);
9626430a94eSMasami Hiramatsu 	}
9636430a94eSMasami Hiramatsu 	cleanup_sdt_note_list(&sdtlist);
9646430a94eSMasami Hiramatsu 	return ret;
9656430a94eSMasami Hiramatsu }
9661c1a3a47SArnaldo Carvalho de Melo #endif
9676430a94eSMasami Hiramatsu 
probe_cache_entry__write(struct probe_cache_entry * entry,int fd)968dd975497SMasami Hiramatsu static int probe_cache_entry__write(struct probe_cache_entry *entry, int fd)
969dd975497SMasami Hiramatsu {
970dd975497SMasami Hiramatsu 	struct str_node *snode;
971dd975497SMasami Hiramatsu 	struct stat st;
972dd975497SMasami Hiramatsu 	struct iovec iov[3];
9736430a94eSMasami Hiramatsu 	const char *prefix = entry->sdt ? "%" : "#";
974dd975497SMasami Hiramatsu 	int ret;
975dd975497SMasami Hiramatsu 	/* Save stat for rollback */
976dd975497SMasami Hiramatsu 	ret = fstat(fd, &st);
977dd975497SMasami Hiramatsu 	if (ret < 0)
978dd975497SMasami Hiramatsu 		return ret;
979dd975497SMasami Hiramatsu 
9806430a94eSMasami Hiramatsu 	pr_debug("Writing cache: %s%s\n", prefix, entry->spev);
9816430a94eSMasami Hiramatsu 	iov[0].iov_base = (void *)prefix; iov[0].iov_len = 1;
982dd975497SMasami Hiramatsu 	iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev);
983dd975497SMasami Hiramatsu 	iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1;
984dd975497SMasami Hiramatsu 	ret = writev(fd, iov, 3);
985dd975497SMasami Hiramatsu 	if (ret < (int)iov[1].iov_len + 2)
986dd975497SMasami Hiramatsu 		goto rollback;
987dd975497SMasami Hiramatsu 
988602a1f4dSArnaldo Carvalho de Melo 	strlist__for_each_entry(snode, entry->tevlist) {
989dd975497SMasami Hiramatsu 		iov[0].iov_base = (void *)snode->s;
990dd975497SMasami Hiramatsu 		iov[0].iov_len = strlen(snode->s);
991dd975497SMasami Hiramatsu 		iov[1].iov_base = (void *)"\n"; iov[1].iov_len = 1;
992dd975497SMasami Hiramatsu 		ret = writev(fd, iov, 2);
993dd975497SMasami Hiramatsu 		if (ret < (int)iov[0].iov_len + 1)
994dd975497SMasami Hiramatsu 			goto rollback;
995dd975497SMasami Hiramatsu 	}
996dd975497SMasami Hiramatsu 	return 0;
997dd975497SMasami Hiramatsu 
998dd975497SMasami Hiramatsu rollback:
999dd975497SMasami Hiramatsu 	/* Rollback to avoid cache file corruption */
1000dd975497SMasami Hiramatsu 	if (ret > 0)
1001dd975497SMasami Hiramatsu 		ret = -1;
1002dd975497SMasami Hiramatsu 	if (ftruncate(fd, st.st_size) < 0)
1003dd975497SMasami Hiramatsu 		ret = -2;
1004dd975497SMasami Hiramatsu 
1005dd975497SMasami Hiramatsu 	return ret;
1006dd975497SMasami Hiramatsu }
1007dd975497SMasami Hiramatsu 
probe_cache__commit(struct probe_cache * pcache)1008dd975497SMasami Hiramatsu int probe_cache__commit(struct probe_cache *pcache)
1009dd975497SMasami Hiramatsu {
1010dd975497SMasami Hiramatsu 	struct probe_cache_entry *entry;
1011dd975497SMasami Hiramatsu 	int ret = 0;
1012dd975497SMasami Hiramatsu 
1013dd975497SMasami Hiramatsu 	/* TBD: if we do not update existing entries, skip it */
1014dd975497SMasami Hiramatsu 	ret = lseek(pcache->fd, 0, SEEK_SET);
1015dd975497SMasami Hiramatsu 	if (ret < 0)
1016dd975497SMasami Hiramatsu 		goto out;
1017dd975497SMasami Hiramatsu 
1018dd975497SMasami Hiramatsu 	ret = ftruncate(pcache->fd, 0);
1019dd975497SMasami Hiramatsu 	if (ret < 0)
1020dd975497SMasami Hiramatsu 		goto out;
1021dd975497SMasami Hiramatsu 
102205bf2c8aSMasami Hiramatsu 	for_each_probe_cache_entry(entry, pcache) {
1023dd975497SMasami Hiramatsu 		ret = probe_cache_entry__write(entry, pcache->fd);
1024dd975497SMasami Hiramatsu 		pr_debug("Cache committed: %d\n", ret);
1025dd975497SMasami Hiramatsu 		if (ret < 0)
1026dd975497SMasami Hiramatsu 			break;
1027dd975497SMasami Hiramatsu 	}
1028dd975497SMasami Hiramatsu out:
1029dd975497SMasami Hiramatsu 	return ret;
1030dd975497SMasami Hiramatsu }
10311f3736c9SMasami Hiramatsu 
probe_cache_entry__compare(struct probe_cache_entry * entry,struct strfilter * filter)10324a0f65c1SMasami Hiramatsu static bool probe_cache_entry__compare(struct probe_cache_entry *entry,
10334a0f65c1SMasami Hiramatsu 				       struct strfilter *filter)
10344a0f65c1SMasami Hiramatsu {
10354a0f65c1SMasami Hiramatsu 	char buf[128], *ptr = entry->spev;
10364a0f65c1SMasami Hiramatsu 
10374a0f65c1SMasami Hiramatsu 	if (entry->pev.event) {
10384a0f65c1SMasami Hiramatsu 		snprintf(buf, 128, "%s:%s", entry->pev.group, entry->pev.event);
10394a0f65c1SMasami Hiramatsu 		ptr = buf;
10404a0f65c1SMasami Hiramatsu 	}
10414a0f65c1SMasami Hiramatsu 	return strfilter__compare(filter, ptr);
10424a0f65c1SMasami Hiramatsu }
10434a0f65c1SMasami Hiramatsu 
probe_cache__filter_purge(struct probe_cache * pcache,struct strfilter * filter)10444a0f65c1SMasami Hiramatsu int probe_cache__filter_purge(struct probe_cache *pcache,
10454a0f65c1SMasami Hiramatsu 			      struct strfilter *filter)
10464a0f65c1SMasami Hiramatsu {
10474a0f65c1SMasami Hiramatsu 	struct probe_cache_entry *entry, *tmp;
10484a0f65c1SMasami Hiramatsu 
10494a0f65c1SMasami Hiramatsu 	list_for_each_entry_safe(entry, tmp, &pcache->entries, node) {
10504a0f65c1SMasami Hiramatsu 		if (probe_cache_entry__compare(entry, filter)) {
10514a0f65c1SMasami Hiramatsu 			pr_info("Removed cached event: %s\n", entry->spev);
10524a0f65c1SMasami Hiramatsu 			list_del_init(&entry->node);
10534a0f65c1SMasami Hiramatsu 			probe_cache_entry__delete(entry);
10544a0f65c1SMasami Hiramatsu 		}
10554a0f65c1SMasami Hiramatsu 	}
10564a0f65c1SMasami Hiramatsu 	return 0;
10574a0f65c1SMasami Hiramatsu }
10584a0f65c1SMasami Hiramatsu 
probe_cache__show_entries(struct probe_cache * pcache,struct strfilter * filter)10591f3736c9SMasami Hiramatsu static int probe_cache__show_entries(struct probe_cache *pcache,
10601f3736c9SMasami Hiramatsu 				     struct strfilter *filter)
10611f3736c9SMasami Hiramatsu {
10621f3736c9SMasami Hiramatsu 	struct probe_cache_entry *entry;
10631f3736c9SMasami Hiramatsu 
106405bf2c8aSMasami Hiramatsu 	for_each_probe_cache_entry(entry, pcache) {
10654a0f65c1SMasami Hiramatsu 		if (probe_cache_entry__compare(entry, filter))
10661f3736c9SMasami Hiramatsu 			printf("%s\n", entry->spev);
10671f3736c9SMasami Hiramatsu 	}
10681f3736c9SMasami Hiramatsu 	return 0;
10691f3736c9SMasami Hiramatsu }
10701f3736c9SMasami Hiramatsu 
10711f3736c9SMasami Hiramatsu /* Show all cached probes */
probe_cache__show_all_caches(struct strfilter * filter)10721f3736c9SMasami Hiramatsu int probe_cache__show_all_caches(struct strfilter *filter)
10731f3736c9SMasami Hiramatsu {
10741f3736c9SMasami Hiramatsu 	struct probe_cache *pcache;
10751f3736c9SMasami Hiramatsu 	struct strlist *bidlist;
10761f3736c9SMasami Hiramatsu 	struct str_node *nd;
10771f3736c9SMasami Hiramatsu 	char *buf = strfilter__string(filter);
10781f3736c9SMasami Hiramatsu 
10791f3736c9SMasami Hiramatsu 	pr_debug("list cache with filter: %s\n", buf);
10801f3736c9SMasami Hiramatsu 	free(buf);
10811f3736c9SMasami Hiramatsu 
1082c3492a3aSMasami Hiramatsu 	bidlist = build_id_cache__list_all(true);
10831f3736c9SMasami Hiramatsu 	if (!bidlist) {
10841f3736c9SMasami Hiramatsu 		pr_debug("Failed to get buildids: %d\n", errno);
10851f3736c9SMasami Hiramatsu 		return -EINVAL;
10861f3736c9SMasami Hiramatsu 	}
10871f3736c9SMasami Hiramatsu 	strlist__for_each_entry(nd, bidlist) {
1088f045b8c4SKrister Johansen 		pcache = probe_cache__new(nd->s, NULL);
10891f3736c9SMasami Hiramatsu 		if (!pcache)
10901f3736c9SMasami Hiramatsu 			continue;
10911f3736c9SMasami Hiramatsu 		if (!list_empty(&pcache->entries)) {
10921f3736c9SMasami Hiramatsu 			buf = build_id_cache__origname(nd->s);
10931f3736c9SMasami Hiramatsu 			printf("%s (%s):\n", buf, nd->s);
10941f3736c9SMasami Hiramatsu 			free(buf);
10951f3736c9SMasami Hiramatsu 			probe_cache__show_entries(pcache, filter);
10961f3736c9SMasami Hiramatsu 		}
10971f3736c9SMasami Hiramatsu 		probe_cache__delete(pcache);
10981f3736c9SMasami Hiramatsu 	}
10991f3736c9SMasami Hiramatsu 	strlist__delete(bidlist);
11001f3736c9SMasami Hiramatsu 
11011f3736c9SMasami Hiramatsu 	return 0;
11021f3736c9SMasami Hiramatsu }
1103180b2061SMasami Hiramatsu 
11043da3ea7aSNaveen N. Rao enum ftrace_readme {
11053da3ea7aSNaveen N. Rao 	FTRACE_README_PROBE_TYPE_X = 0,
11067ab31d94SNaveen N. Rao 	FTRACE_README_KRETPROBE_OFFSET,
11075a5e3d3cSRavi Bangoria 	FTRACE_README_UPROBE_REF_CTR,
11081e032f7cSMasami Hiramatsu 	FTRACE_README_USER_ACCESS,
110972363540SMasami Hiramatsu 	FTRACE_README_MULTIPROBE_EVENT,
111066f69b21SMasami Hiramatsu 	FTRACE_README_IMMEDIATE_VALUE,
11113da3ea7aSNaveen N. Rao 	FTRACE_README_END,
11123da3ea7aSNaveen N. Rao };
11133da3ea7aSNaveen N. Rao 
1114180b2061SMasami Hiramatsu static struct {
1115180b2061SMasami Hiramatsu 	const char *pattern;
1116180b2061SMasami Hiramatsu 	bool avail;
11173da3ea7aSNaveen N. Rao } ftrace_readme_table[] = {
11183da3ea7aSNaveen N. Rao #define DEFINE_TYPE(idx, pat)			\
11193da3ea7aSNaveen N. Rao 	[idx] = {.pattern = pat, .avail = false}
11203da3ea7aSNaveen N. Rao 	DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"),
11217ab31d94SNaveen N. Rao 	DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"),
11225a5e3d3cSRavi Bangoria 	DEFINE_TYPE(FTRACE_README_UPROBE_REF_CTR, "*ref_ctr_offset*"),
11239256c303SSumanth Korikkar 	DEFINE_TYPE(FTRACE_README_USER_ACCESS, "*u]<offset>*"),
112472363540SMasami Hiramatsu 	DEFINE_TYPE(FTRACE_README_MULTIPROBE_EVENT, "*Create/append/*"),
112566f69b21SMasami Hiramatsu 	DEFINE_TYPE(FTRACE_README_IMMEDIATE_VALUE, "*\\imm-value,*"),
1126180b2061SMasami Hiramatsu };
1127180b2061SMasami Hiramatsu 
scan_ftrace_readme(enum ftrace_readme type)11283da3ea7aSNaveen N. Rao static bool scan_ftrace_readme(enum ftrace_readme type)
1129180b2061SMasami Hiramatsu {
11303da3ea7aSNaveen N. Rao 	int fd;
1131180b2061SMasami Hiramatsu 	FILE *fp;
1132180b2061SMasami Hiramatsu 	char *buf = NULL;
1133180b2061SMasami Hiramatsu 	size_t len = 0;
11343da3ea7aSNaveen N. Rao 	bool ret = false;
11353da3ea7aSNaveen N. Rao 	static bool scanned = false;
1136180b2061SMasami Hiramatsu 
11373da3ea7aSNaveen N. Rao 	if (scanned)
11383da3ea7aSNaveen N. Rao 		goto result;
1139180b2061SMasami Hiramatsu 
1140e491bc2fSNaveen N. Rao 	fd = open_trace_file("README", false);
1141e491bc2fSNaveen N. Rao 	if (fd < 0)
1142180b2061SMasami Hiramatsu 		return ret;
1143180b2061SMasami Hiramatsu 
1144e491bc2fSNaveen N. Rao 	fp = fdopen(fd, "r");
1145e491bc2fSNaveen N. Rao 	if (!fp) {
1146e491bc2fSNaveen N. Rao 		close(fd);
1147e491bc2fSNaveen N. Rao 		return ret;
1148e491bc2fSNaveen N. Rao 	}
1149180b2061SMasami Hiramatsu 
11503da3ea7aSNaveen N. Rao 	while (getline(&buf, &len, fp) > 0)
11513da3ea7aSNaveen N. Rao 		for (enum ftrace_readme i = 0; i < FTRACE_README_END; i++)
11523da3ea7aSNaveen N. Rao 			if (!ftrace_readme_table[i].avail)
11533da3ea7aSNaveen N. Rao 				ftrace_readme_table[i].avail =
11543da3ea7aSNaveen N. Rao 					strglobmatch(buf, ftrace_readme_table[i].pattern);
11553da3ea7aSNaveen N. Rao 	scanned = true;
1156180b2061SMasami Hiramatsu 
1157180b2061SMasami Hiramatsu 	fclose(fp);
1158180b2061SMasami Hiramatsu 	free(buf);
1159180b2061SMasami Hiramatsu 
11603da3ea7aSNaveen N. Rao result:
11613da3ea7aSNaveen N. Rao 	if (type >= FTRACE_README_END)
11623da3ea7aSNaveen N. Rao 		return false;
11633da3ea7aSNaveen N. Rao 
11643da3ea7aSNaveen N. Rao 	return ftrace_readme_table[type].avail;
11653da3ea7aSNaveen N. Rao }
11663da3ea7aSNaveen N. Rao 
probe_type_is_available(enum probe_type type)11673da3ea7aSNaveen N. Rao bool probe_type_is_available(enum probe_type type)
11683da3ea7aSNaveen N. Rao {
11693da3ea7aSNaveen N. Rao 	if (type >= PROBE_TYPE_END)
11703da3ea7aSNaveen N. Rao 		return false;
11713da3ea7aSNaveen N. Rao 	else if (type == PROBE_TYPE_X)
11723da3ea7aSNaveen N. Rao 		return scan_ftrace_readme(FTRACE_README_PROBE_TYPE_X);
11733da3ea7aSNaveen N. Rao 
11743da3ea7aSNaveen N. Rao 	return true;
1175180b2061SMasami Hiramatsu }
11767ab31d94SNaveen N. Rao 
kretprobe_offset_is_supported(void)11777ab31d94SNaveen N. Rao bool kretprobe_offset_is_supported(void)
11787ab31d94SNaveen N. Rao {
11797ab31d94SNaveen N. Rao 	return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET);
11807ab31d94SNaveen N. Rao }
11815a5e3d3cSRavi Bangoria 
uprobe_ref_ctr_is_supported(void)11825a5e3d3cSRavi Bangoria bool uprobe_ref_ctr_is_supported(void)
11835a5e3d3cSRavi Bangoria {
11845a5e3d3cSRavi Bangoria 	return scan_ftrace_readme(FTRACE_README_UPROBE_REF_CTR);
11855a5e3d3cSRavi Bangoria }
11861e032f7cSMasami Hiramatsu 
user_access_is_supported(void)11871e032f7cSMasami Hiramatsu bool user_access_is_supported(void)
11881e032f7cSMasami Hiramatsu {
11891e032f7cSMasami Hiramatsu 	return scan_ftrace_readme(FTRACE_README_USER_ACCESS);
11901e032f7cSMasami Hiramatsu }
119172363540SMasami Hiramatsu 
multiprobe_event_is_supported(void)119272363540SMasami Hiramatsu bool multiprobe_event_is_supported(void)
119372363540SMasami Hiramatsu {
119472363540SMasami Hiramatsu 	return scan_ftrace_readme(FTRACE_README_MULTIPROBE_EVENT);
119572363540SMasami Hiramatsu }
119666f69b21SMasami Hiramatsu 
immediate_value_is_supported(void)119766f69b21SMasami Hiramatsu bool immediate_value_is_supported(void)
119866f69b21SMasami Hiramatsu {
119966f69b21SMasami Hiramatsu 	return scan_ftrace_readme(FTRACE_README_IMMEDIATE_VALUE);
120066f69b21SMasami Hiramatsu }
1201