xref: /linux/tools/perf/util/probe-event.c (revision 6eca8cc35b50af1037bc919106dd6dd332c959c2)
150656eecSMasami Hiramatsu /*
250656eecSMasami Hiramatsu  * probe-event.c : perf-probe definition to kprobe_events format converter
350656eecSMasami Hiramatsu  *
450656eecSMasami Hiramatsu  * Written by Masami Hiramatsu <mhiramat@redhat.com>
550656eecSMasami Hiramatsu  *
650656eecSMasami Hiramatsu  * This program is free software; you can redistribute it and/or modify
750656eecSMasami Hiramatsu  * it under the terms of the GNU General Public License as published by
850656eecSMasami Hiramatsu  * the Free Software Foundation; either version 2 of the License, or
950656eecSMasami Hiramatsu  * (at your option) any later version.
1050656eecSMasami Hiramatsu  *
1150656eecSMasami Hiramatsu  * This program is distributed in the hope that it will be useful,
1250656eecSMasami Hiramatsu  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1350656eecSMasami Hiramatsu  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1450656eecSMasami Hiramatsu  * GNU General Public License for more details.
1550656eecSMasami Hiramatsu  *
1650656eecSMasami Hiramatsu  * You should have received a copy of the GNU General Public License
1750656eecSMasami Hiramatsu  * along with this program; if not, write to the Free Software
1850656eecSMasami Hiramatsu  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1950656eecSMasami Hiramatsu  *
2050656eecSMasami Hiramatsu  */
2150656eecSMasami Hiramatsu 
2250656eecSMasami Hiramatsu #define _GNU_SOURCE
2350656eecSMasami Hiramatsu #include <sys/utsname.h>
2450656eecSMasami Hiramatsu #include <sys/types.h>
2550656eecSMasami Hiramatsu #include <sys/stat.h>
2650656eecSMasami Hiramatsu #include <fcntl.h>
2750656eecSMasami Hiramatsu #include <errno.h>
2850656eecSMasami Hiramatsu #include <stdio.h>
2950656eecSMasami Hiramatsu #include <unistd.h>
3050656eecSMasami Hiramatsu #include <stdlib.h>
3150656eecSMasami Hiramatsu #include <string.h>
324de189feSMasami Hiramatsu #include <stdarg.h>
334de189feSMasami Hiramatsu #include <limits.h>
3450656eecSMasami Hiramatsu 
3550656eecSMasami Hiramatsu #undef _GNU_SOURCE
3631facc5fSMasami Hiramatsu #include "util.h"
3750656eecSMasami Hiramatsu #include "event.h"
38e1c01d61SMasami Hiramatsu #include "string.h"
394de189feSMasami Hiramatsu #include "strlist.h"
4050656eecSMasami Hiramatsu #include "debug.h"
4172041334SMasami Hiramatsu #include "cache.h"
42631c9defSMasami Hiramatsu #include "color.h"
43e0faa8d3SMasami Hiramatsu #include "symbol.h"
44e0faa8d3SMasami Hiramatsu #include "thread.h"
457ca5989dSMasami Hiramatsu #include "debugfs.h"
464b4da7f7SMasami Hiramatsu #include "trace-event.h"	/* For __unused */
4750656eecSMasami Hiramatsu #include "probe-event.h"
484235b045SMasami Hiramatsu #include "probe-finder.h"
4950656eecSMasami Hiramatsu 
5050656eecSMasami Hiramatsu #define MAX_CMDLEN 256
5150656eecSMasami Hiramatsu #define MAX_PROBE_ARGS 128
5250656eecSMasami Hiramatsu #define PERFPROBE_GROUP "probe"
5350656eecSMasami Hiramatsu 
54f4d7da49SMasami Hiramatsu bool probe_event_dry_run;	/* Dry run flag */
55f4d7da49SMasami Hiramatsu 
56146a1439SMasami Hiramatsu #define semantic_error(msg ...) pr_err("Semantic error :" msg)
5750656eecSMasami Hiramatsu 
584de189feSMasami Hiramatsu /* If there is no space to write, returns -E2BIG. */
594de189feSMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...)
6084988450SMasami Hiramatsu 	__attribute__((format(printf, 3, 4)));
6184988450SMasami Hiramatsu 
6284988450SMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...)
634de189feSMasami Hiramatsu {
644de189feSMasami Hiramatsu 	int ret;
654de189feSMasami Hiramatsu 	va_list ap;
664de189feSMasami Hiramatsu 	va_start(ap, format);
674de189feSMasami Hiramatsu 	ret = vsnprintf(str, size, format, ap);
684de189feSMasami Hiramatsu 	va_end(ap);
694de189feSMasami Hiramatsu 	if (ret >= (int)size)
704de189feSMasami Hiramatsu 		ret = -E2BIG;
714de189feSMasami Hiramatsu 	return ret;
724de189feSMasami Hiramatsu }
734de189feSMasami Hiramatsu 
744b4da7f7SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
75e0faa8d3SMasami Hiramatsu static struct map_groups kmap_groups;
76e0faa8d3SMasami Hiramatsu static struct map *kmaps[MAP__NR_TYPES];
77e0faa8d3SMasami Hiramatsu 
784b4da7f7SMasami Hiramatsu /* Initialize symbol maps and path of vmlinux */
79146a1439SMasami Hiramatsu static int init_vmlinux(void)
80e0faa8d3SMasami Hiramatsu {
81a1645ce1SZhang, Yanmin 	struct dso *kernel;
82146a1439SMasami Hiramatsu 	int ret;
83146a1439SMasami Hiramatsu 
84e0faa8d3SMasami Hiramatsu 	symbol_conf.sort_by_name = true;
85e0faa8d3SMasami Hiramatsu 	if (symbol_conf.vmlinux_name == NULL)
86e0faa8d3SMasami Hiramatsu 		symbol_conf.try_vmlinux_path = true;
87e0faa8d3SMasami Hiramatsu 	else
88e0faa8d3SMasami Hiramatsu 		pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
89146a1439SMasami Hiramatsu 	ret = symbol__init();
90146a1439SMasami Hiramatsu 	if (ret < 0) {
91146a1439SMasami Hiramatsu 		pr_debug("Failed to init symbol map.\n");
92146a1439SMasami Hiramatsu 		goto out;
93146a1439SMasami Hiramatsu 	}
94e0faa8d3SMasami Hiramatsu 
95a1645ce1SZhang, Yanmin 	kernel = dso__new_kernel(symbol_conf.vmlinux_name);
96a1645ce1SZhang, Yanmin 	if (kernel == NULL)
97a1645ce1SZhang, Yanmin 		die("Failed to create kernel dso.");
98a1645ce1SZhang, Yanmin 
99e0faa8d3SMasami Hiramatsu 	map_groups__init(&kmap_groups);
100a1645ce1SZhang, Yanmin 	ret = __map_groups__create_kernel_maps(&kmap_groups, kmaps, kernel);
101146a1439SMasami Hiramatsu 	if (ret < 0)
102146a1439SMasami Hiramatsu 		pr_debug("Failed to create kernel maps.\n");
103146a1439SMasami Hiramatsu 
104146a1439SMasami Hiramatsu out:
105146a1439SMasami Hiramatsu 	if (ret < 0)
106146a1439SMasami Hiramatsu 		pr_warning("Failed to init vmlinux path.\n");
107146a1439SMasami Hiramatsu 	return ret;
108e0faa8d3SMasami Hiramatsu }
109e0faa8d3SMasami Hiramatsu 
1104b4da7f7SMasami Hiramatsu #ifdef DWARF_SUPPORT
111e0faa8d3SMasami Hiramatsu static int open_vmlinux(void)
112e0faa8d3SMasami Hiramatsu {
113e0faa8d3SMasami Hiramatsu 	if (map__load(kmaps[MAP__FUNCTION], NULL) < 0) {
114e0faa8d3SMasami Hiramatsu 		pr_debug("Failed to load kernel map.\n");
115e0faa8d3SMasami Hiramatsu 		return -EINVAL;
116e0faa8d3SMasami Hiramatsu 	}
117e0faa8d3SMasami Hiramatsu 	pr_debug("Try to open %s\n", kmaps[MAP__FUNCTION]->dso->long_name);
118e0faa8d3SMasami Hiramatsu 	return open(kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
119e0faa8d3SMasami Hiramatsu }
1204b4da7f7SMasami Hiramatsu 
121146a1439SMasami Hiramatsu /* Convert trace point to probe point with debuginfo */
122146a1439SMasami Hiramatsu static int convert_to_perf_probe_point(struct kprobe_trace_point *tp,
1234b4da7f7SMasami Hiramatsu 				       struct perf_probe_point *pp)
1244b4da7f7SMasami Hiramatsu {
1254b4da7f7SMasami Hiramatsu 	struct symbol *sym;
126146a1439SMasami Hiramatsu 	int fd, ret = -ENOENT;
1274b4da7f7SMasami Hiramatsu 
1284b4da7f7SMasami Hiramatsu 	sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
1294b4da7f7SMasami Hiramatsu 				       tp->symbol, NULL);
1304b4da7f7SMasami Hiramatsu 	if (sym) {
1314b4da7f7SMasami Hiramatsu 		fd = open_vmlinux();
132146a1439SMasami Hiramatsu 		if (fd >= 0) {
133146a1439SMasami Hiramatsu 			ret = find_perf_probe_point(fd,
134146a1439SMasami Hiramatsu 						 sym->start + tp->offset, pp);
1354b4da7f7SMasami Hiramatsu 			close(fd);
1364b4da7f7SMasami Hiramatsu 		}
137146a1439SMasami Hiramatsu 	}
1384b4da7f7SMasami Hiramatsu 	if (ret <= 0) {
139146a1439SMasami Hiramatsu 		pr_debug("Failed to find corresponding probes from "
140146a1439SMasami Hiramatsu 			 "debuginfo. Use kprobe event information.\n");
14102b95dadSMasami Hiramatsu 		pp->function = strdup(tp->symbol);
14202b95dadSMasami Hiramatsu 		if (pp->function == NULL)
14302b95dadSMasami Hiramatsu 			return -ENOMEM;
1444b4da7f7SMasami Hiramatsu 		pp->offset = tp->offset;
1454b4da7f7SMasami Hiramatsu 	}
1464b4da7f7SMasami Hiramatsu 	pp->retprobe = tp->retprobe;
147146a1439SMasami Hiramatsu 
148146a1439SMasami Hiramatsu 	return 0;
1494b4da7f7SMasami Hiramatsu }
1504b4da7f7SMasami Hiramatsu 
1514b4da7f7SMasami Hiramatsu /* Try to find perf_probe_event with debuginfo */
1524b4da7f7SMasami Hiramatsu static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
1534b4da7f7SMasami Hiramatsu 					   struct kprobe_trace_event **tevs)
1544b4da7f7SMasami Hiramatsu {
1554b4da7f7SMasami Hiramatsu 	bool need_dwarf = perf_probe_event_need_dwarf(pev);
1564b4da7f7SMasami Hiramatsu 	int fd, ntevs;
1574b4da7f7SMasami Hiramatsu 
1584b4da7f7SMasami Hiramatsu 	fd = open_vmlinux();
1594b4da7f7SMasami Hiramatsu 	if (fd < 0) {
160146a1439SMasami Hiramatsu 		if (need_dwarf) {
161146a1439SMasami Hiramatsu 			pr_warning("Failed to open debuginfo file.\n");
162146a1439SMasami Hiramatsu 			return fd;
163146a1439SMasami Hiramatsu 		}
1644b4da7f7SMasami Hiramatsu 		pr_debug("Could not open vmlinux. Try to use symbols.\n");
1654b4da7f7SMasami Hiramatsu 		return 0;
1664b4da7f7SMasami Hiramatsu 	}
1674b4da7f7SMasami Hiramatsu 
1684b4da7f7SMasami Hiramatsu 	/* Searching trace events corresponding to probe event */
1694b4da7f7SMasami Hiramatsu 	ntevs = find_kprobe_trace_events(fd, pev, tevs);
1704b4da7f7SMasami Hiramatsu 	close(fd);
1714b4da7f7SMasami Hiramatsu 
172146a1439SMasami Hiramatsu 	if (ntevs > 0) {	/* Succeeded to find trace events */
173146a1439SMasami Hiramatsu 		pr_debug("find %d kprobe_trace_events.\n", ntevs);
1744b4da7f7SMasami Hiramatsu 		return ntevs;
175146a1439SMasami Hiramatsu 	}
1764b4da7f7SMasami Hiramatsu 
177146a1439SMasami Hiramatsu 	if (ntevs == 0)	{	/* No error but failed to find probe point. */
178146a1439SMasami Hiramatsu 		pr_warning("Probe point '%s' not found.\n",
1794b4da7f7SMasami Hiramatsu 			   synthesize_perf_probe_point(&pev->point));
180146a1439SMasami Hiramatsu 		return -ENOENT;
181146a1439SMasami Hiramatsu 	}
182146a1439SMasami Hiramatsu 	/* Error path : ntevs < 0 */
1834b4da7f7SMasami Hiramatsu 	if (need_dwarf) {
184b55a87adSMasami Hiramatsu 		if (ntevs == -EBADF)
1854b4da7f7SMasami Hiramatsu 			pr_warning("No dwarf info found in the vmlinux - "
1864b4da7f7SMasami Hiramatsu 				"please rebuild with CONFIG_DEBUG_INFO=y.\n");
187146a1439SMasami Hiramatsu 		return ntevs;
1884b4da7f7SMasami Hiramatsu 	}
1894b4da7f7SMasami Hiramatsu 	pr_debug("An error occurred in debuginfo analysis."
1904b4da7f7SMasami Hiramatsu 		 " Try to use symbols.\n");
1914b4da7f7SMasami Hiramatsu 	return 0;
1924b4da7f7SMasami Hiramatsu }
1934b4da7f7SMasami Hiramatsu 
1944b4da7f7SMasami Hiramatsu #define LINEBUF_SIZE 256
1954b4da7f7SMasami Hiramatsu #define NR_ADDITIONAL_LINES 2
1964b4da7f7SMasami Hiramatsu 
197d3b63d7aSMasami Hiramatsu static int show_one_line(FILE *fp, int l, bool skip, bool show_num)
1984b4da7f7SMasami Hiramatsu {
1994b4da7f7SMasami Hiramatsu 	char buf[LINEBUF_SIZE];
2004b4da7f7SMasami Hiramatsu 	const char *color = PERF_COLOR_BLUE;
2014b4da7f7SMasami Hiramatsu 
2024b4da7f7SMasami Hiramatsu 	if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
2034b4da7f7SMasami Hiramatsu 		goto error;
2044b4da7f7SMasami Hiramatsu 	if (!skip) {
2054b4da7f7SMasami Hiramatsu 		if (show_num)
206d3b63d7aSMasami Hiramatsu 			fprintf(stdout, "%7d  %s", l, buf);
2074b4da7f7SMasami Hiramatsu 		else
2084b4da7f7SMasami Hiramatsu 			color_fprintf(stdout, color, "         %s", buf);
2094b4da7f7SMasami Hiramatsu 	}
2104b4da7f7SMasami Hiramatsu 
2114b4da7f7SMasami Hiramatsu 	while (strlen(buf) == LINEBUF_SIZE - 1 &&
2124b4da7f7SMasami Hiramatsu 	       buf[LINEBUF_SIZE - 2] != '\n') {
2134b4da7f7SMasami Hiramatsu 		if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
2144b4da7f7SMasami Hiramatsu 			goto error;
2154b4da7f7SMasami Hiramatsu 		if (!skip) {
2164b4da7f7SMasami Hiramatsu 			if (show_num)
2174b4da7f7SMasami Hiramatsu 				fprintf(stdout, "%s", buf);
2184b4da7f7SMasami Hiramatsu 			else
2194b4da7f7SMasami Hiramatsu 				color_fprintf(stdout, color, "%s", buf);
2204b4da7f7SMasami Hiramatsu 		}
2214b4da7f7SMasami Hiramatsu 	}
222146a1439SMasami Hiramatsu 
223146a1439SMasami Hiramatsu 	return 0;
2244b4da7f7SMasami Hiramatsu error:
2254b4da7f7SMasami Hiramatsu 	if (feof(fp))
226146a1439SMasami Hiramatsu 		pr_warning("Source file is shorter than expected.\n");
2274b4da7f7SMasami Hiramatsu 	else
228146a1439SMasami Hiramatsu 		pr_warning("File read error: %s\n", strerror(errno));
229146a1439SMasami Hiramatsu 
230146a1439SMasami Hiramatsu 	return -1;
2314b4da7f7SMasami Hiramatsu }
2324b4da7f7SMasami Hiramatsu 
2334b4da7f7SMasami Hiramatsu /*
2344b4da7f7SMasami Hiramatsu  * Show line-range always requires debuginfo to find source file and
2354b4da7f7SMasami Hiramatsu  * line number.
2364b4da7f7SMasami Hiramatsu  */
237146a1439SMasami Hiramatsu int show_line_range(struct line_range *lr)
2384b4da7f7SMasami Hiramatsu {
239d3b63d7aSMasami Hiramatsu 	int l = 1;
2404b4da7f7SMasami Hiramatsu 	struct line_node *ln;
2414b4da7f7SMasami Hiramatsu 	FILE *fp;
2424b4da7f7SMasami Hiramatsu 	int fd, ret;
2434b4da7f7SMasami Hiramatsu 
2444b4da7f7SMasami Hiramatsu 	/* Search a line range */
245146a1439SMasami Hiramatsu 	ret = init_vmlinux();
246146a1439SMasami Hiramatsu 	if (ret < 0)
247146a1439SMasami Hiramatsu 		return ret;
248146a1439SMasami Hiramatsu 
2494b4da7f7SMasami Hiramatsu 	fd = open_vmlinux();
250146a1439SMasami Hiramatsu 	if (fd < 0) {
251146a1439SMasami Hiramatsu 		pr_warning("Failed to open debuginfo file.\n");
252146a1439SMasami Hiramatsu 		return fd;
253146a1439SMasami Hiramatsu 	}
254146a1439SMasami Hiramatsu 
2554b4da7f7SMasami Hiramatsu 	ret = find_line_range(fd, lr);
2564b4da7f7SMasami Hiramatsu 	close(fd);
257146a1439SMasami Hiramatsu 	if (ret == 0) {
258146a1439SMasami Hiramatsu 		pr_warning("Specified source line is not found.\n");
259146a1439SMasami Hiramatsu 		return -ENOENT;
260146a1439SMasami Hiramatsu 	} else if (ret < 0) {
261146a1439SMasami Hiramatsu 		pr_warning("Debuginfo analysis failed. (%d)\n", ret);
262146a1439SMasami Hiramatsu 		return ret;
263146a1439SMasami Hiramatsu 	}
2644b4da7f7SMasami Hiramatsu 
2654b4da7f7SMasami Hiramatsu 	setup_pager();
2664b4da7f7SMasami Hiramatsu 
2674b4da7f7SMasami Hiramatsu 	if (lr->function)
2684b4da7f7SMasami Hiramatsu 		fprintf(stdout, "<%s:%d>\n", lr->function,
2694b4da7f7SMasami Hiramatsu 			lr->start - lr->offset);
2704b4da7f7SMasami Hiramatsu 	else
2714b4da7f7SMasami Hiramatsu 		fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
2724b4da7f7SMasami Hiramatsu 
2734b4da7f7SMasami Hiramatsu 	fp = fopen(lr->path, "r");
274146a1439SMasami Hiramatsu 	if (fp == NULL) {
275146a1439SMasami Hiramatsu 		pr_warning("Failed to open %s: %s\n", lr->path,
276146a1439SMasami Hiramatsu 			   strerror(errno));
277146a1439SMasami Hiramatsu 		return -errno;
278146a1439SMasami Hiramatsu 	}
2794b4da7f7SMasami Hiramatsu 	/* Skip to starting line number */
280146a1439SMasami Hiramatsu 	while (l < lr->start && ret >= 0)
281146a1439SMasami Hiramatsu 		ret = show_one_line(fp, l++, true, false);
282146a1439SMasami Hiramatsu 	if (ret < 0)
283146a1439SMasami Hiramatsu 		goto end;
2844b4da7f7SMasami Hiramatsu 
2854b4da7f7SMasami Hiramatsu 	list_for_each_entry(ln, &lr->line_list, list) {
286146a1439SMasami Hiramatsu 		while (ln->line > l && ret >= 0)
287146a1439SMasami Hiramatsu 			ret = show_one_line(fp, (l++) - lr->offset,
288146a1439SMasami Hiramatsu 					    false, false);
289146a1439SMasami Hiramatsu 		if (ret >= 0)
290146a1439SMasami Hiramatsu 			ret = show_one_line(fp, (l++) - lr->offset,
291146a1439SMasami Hiramatsu 					    false, true);
292146a1439SMasami Hiramatsu 		if (ret < 0)
293146a1439SMasami Hiramatsu 			goto end;
2944b4da7f7SMasami Hiramatsu 	}
2954b4da7f7SMasami Hiramatsu 
2964b4da7f7SMasami Hiramatsu 	if (lr->end == INT_MAX)
2974b4da7f7SMasami Hiramatsu 		lr->end = l + NR_ADDITIONAL_LINES;
298dda4ab34SMasami Hiramatsu 	while (l <= lr->end && !feof(fp) && ret >= 0)
299146a1439SMasami Hiramatsu 		ret = show_one_line(fp, (l++) - lr->offset, false, false);
300146a1439SMasami Hiramatsu end:
3014b4da7f7SMasami Hiramatsu 	fclose(fp);
302146a1439SMasami Hiramatsu 	return ret;
3034b4da7f7SMasami Hiramatsu }
3044b4da7f7SMasami Hiramatsu 
3054b4da7f7SMasami Hiramatsu #else	/* !DWARF_SUPPORT */
3064b4da7f7SMasami Hiramatsu 
307146a1439SMasami Hiramatsu static int convert_to_perf_probe_point(struct kprobe_trace_point *tp,
3084b4da7f7SMasami Hiramatsu 					struct perf_probe_point *pp)
3094b4da7f7SMasami Hiramatsu {
31002b95dadSMasami Hiramatsu 	pp->function = strdup(tp->symbol);
31102b95dadSMasami Hiramatsu 	if (pp->function == NULL)
31202b95dadSMasami Hiramatsu 		return -ENOMEM;
3134b4da7f7SMasami Hiramatsu 	pp->offset = tp->offset;
3144b4da7f7SMasami Hiramatsu 	pp->retprobe = tp->retprobe;
315146a1439SMasami Hiramatsu 
316146a1439SMasami Hiramatsu 	return 0;
3174b4da7f7SMasami Hiramatsu }
3184b4da7f7SMasami Hiramatsu 
3194b4da7f7SMasami Hiramatsu static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
3204b4da7f7SMasami Hiramatsu 				struct kprobe_trace_event **tevs __unused)
3214b4da7f7SMasami Hiramatsu {
322146a1439SMasami Hiramatsu 	if (perf_probe_event_need_dwarf(pev)) {
323146a1439SMasami Hiramatsu 		pr_warning("Debuginfo-analysis is not supported.\n");
324146a1439SMasami Hiramatsu 		return -ENOSYS;
325146a1439SMasami Hiramatsu 	}
3264b4da7f7SMasami Hiramatsu 	return 0;
3274b4da7f7SMasami Hiramatsu }
3284b4da7f7SMasami Hiramatsu 
329146a1439SMasami Hiramatsu int show_line_range(struct line_range *lr __unused)
3304b4da7f7SMasami Hiramatsu {
331146a1439SMasami Hiramatsu 	pr_warning("Debuginfo-analysis is not supported.\n");
332146a1439SMasami Hiramatsu 	return -ENOSYS;
3334b4da7f7SMasami Hiramatsu }
3344b4da7f7SMasami Hiramatsu 
335e0faa8d3SMasami Hiramatsu #endif
336e0faa8d3SMasami Hiramatsu 
337146a1439SMasami Hiramatsu int parse_line_range_desc(const char *arg, struct line_range *lr)
338631c9defSMasami Hiramatsu {
339631c9defSMasami Hiramatsu 	const char *ptr;
340631c9defSMasami Hiramatsu 	char *tmp;
341631c9defSMasami Hiramatsu 	/*
342631c9defSMasami Hiramatsu 	 * <Syntax>
343631c9defSMasami Hiramatsu 	 * SRC:SLN[+NUM|-ELN]
344631c9defSMasami Hiramatsu 	 * FUNC[:SLN[+NUM|-ELN]]
345631c9defSMasami Hiramatsu 	 */
346631c9defSMasami Hiramatsu 	ptr = strchr(arg, ':');
347631c9defSMasami Hiramatsu 	if (ptr) {
348d3b63d7aSMasami Hiramatsu 		lr->start = (int)strtoul(ptr + 1, &tmp, 0);
349dda4ab34SMasami Hiramatsu 		if (*tmp == '+') {
350d3b63d7aSMasami Hiramatsu 			lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0);
351dda4ab34SMasami Hiramatsu 			lr->end--;	/*
352dda4ab34SMasami Hiramatsu 					 * Adjust the number of lines here.
353dda4ab34SMasami Hiramatsu 					 * If the number of lines == 1, the
354dda4ab34SMasami Hiramatsu 					 * the end of line should be equal to
355dda4ab34SMasami Hiramatsu 					 * the start of line.
356dda4ab34SMasami Hiramatsu 					 */
357dda4ab34SMasami Hiramatsu 		} else if (*tmp == '-')
358d3b63d7aSMasami Hiramatsu 			lr->end = (int)strtoul(tmp + 1, &tmp, 0);
359631c9defSMasami Hiramatsu 		else
360d3b63d7aSMasami Hiramatsu 			lr->end = INT_MAX;
361d3b63d7aSMasami Hiramatsu 		pr_debug("Line range is %d to %d\n", lr->start, lr->end);
362d3b63d7aSMasami Hiramatsu 		if (lr->start > lr->end) {
363631c9defSMasami Hiramatsu 			semantic_error("Start line must be smaller"
364146a1439SMasami Hiramatsu 				       " than end line.\n");
365146a1439SMasami Hiramatsu 			return -EINVAL;
366146a1439SMasami Hiramatsu 		}
367146a1439SMasami Hiramatsu 		if (*tmp != '\0') {
368146a1439SMasami Hiramatsu 			semantic_error("Tailing with invalid character '%d'.\n",
369631c9defSMasami Hiramatsu 				       *tmp);
370146a1439SMasami Hiramatsu 			return -EINVAL;
371146a1439SMasami Hiramatsu 		}
37202b95dadSMasami Hiramatsu 		tmp = strndup(arg, (ptr - arg));
373d3b63d7aSMasami Hiramatsu 	} else {
37402b95dadSMasami Hiramatsu 		tmp = strdup(arg);
375d3b63d7aSMasami Hiramatsu 		lr->end = INT_MAX;
376d3b63d7aSMasami Hiramatsu 	}
37702b95dadSMasami Hiramatsu 
37802b95dadSMasami Hiramatsu 	if (tmp == NULL)
37902b95dadSMasami Hiramatsu 		return -ENOMEM;
380631c9defSMasami Hiramatsu 
381631c9defSMasami Hiramatsu 	if (strchr(tmp, '.'))
382631c9defSMasami Hiramatsu 		lr->file = tmp;
383631c9defSMasami Hiramatsu 	else
384631c9defSMasami Hiramatsu 		lr->function = tmp;
385146a1439SMasami Hiramatsu 
386146a1439SMasami Hiramatsu 	return 0;
387631c9defSMasami Hiramatsu }
388631c9defSMasami Hiramatsu 
389b7702a21SMasami Hiramatsu /* Check the name is good for event/group */
390b7702a21SMasami Hiramatsu static bool check_event_name(const char *name)
391b7702a21SMasami Hiramatsu {
392b7702a21SMasami Hiramatsu 	if (!isalpha(*name) && *name != '_')
393b7702a21SMasami Hiramatsu 		return false;
394b7702a21SMasami Hiramatsu 	while (*++name != '\0') {
395b7702a21SMasami Hiramatsu 		if (!isalpha(*name) && !isdigit(*name) && *name != '_')
396b7702a21SMasami Hiramatsu 			return false;
397b7702a21SMasami Hiramatsu 	}
398b7702a21SMasami Hiramatsu 	return true;
399b7702a21SMasami Hiramatsu }
400b7702a21SMasami Hiramatsu 
40150656eecSMasami Hiramatsu /* Parse probepoint definition. */
402146a1439SMasami Hiramatsu static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
40350656eecSMasami Hiramatsu {
4044235b045SMasami Hiramatsu 	struct perf_probe_point *pp = &pev->point;
40550656eecSMasami Hiramatsu 	char *ptr, *tmp;
40650656eecSMasami Hiramatsu 	char c, nc = 0;
40750656eecSMasami Hiramatsu 	/*
40850656eecSMasami Hiramatsu 	 * <Syntax>
4092a9c8c36SMasami Hiramatsu 	 * perf probe [EVENT=]SRC[:LN|;PTN]
4102a9c8c36SMasami Hiramatsu 	 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
411af663d75SMasami Hiramatsu 	 *
412af663d75SMasami Hiramatsu 	 * TODO:Group name support
41350656eecSMasami Hiramatsu 	 */
41450656eecSMasami Hiramatsu 
4152a9c8c36SMasami Hiramatsu 	ptr = strpbrk(arg, ";=@+%");
4162a9c8c36SMasami Hiramatsu 	if (ptr && *ptr == '=') {	/* Event name */
417af663d75SMasami Hiramatsu 		*ptr = '\0';
418af663d75SMasami Hiramatsu 		tmp = ptr + 1;
419146a1439SMasami Hiramatsu 		if (strchr(arg, ':')) {
420146a1439SMasami Hiramatsu 			semantic_error("Group name is not supported yet.\n");
421146a1439SMasami Hiramatsu 			return -ENOTSUP;
422146a1439SMasami Hiramatsu 		}
423146a1439SMasami Hiramatsu 		if (!check_event_name(arg)) {
424b7702a21SMasami Hiramatsu 			semantic_error("%s is bad for event name -it must "
425146a1439SMasami Hiramatsu 				       "follow C symbol-naming rule.\n", arg);
426146a1439SMasami Hiramatsu 			return -EINVAL;
427146a1439SMasami Hiramatsu 		}
42802b95dadSMasami Hiramatsu 		pev->event = strdup(arg);
42902b95dadSMasami Hiramatsu 		if (pev->event == NULL)
43002b95dadSMasami Hiramatsu 			return -ENOMEM;
4314235b045SMasami Hiramatsu 		pev->group = NULL;
432af663d75SMasami Hiramatsu 		arg = tmp;
433af663d75SMasami Hiramatsu 	}
434af663d75SMasami Hiramatsu 
4352a9c8c36SMasami Hiramatsu 	ptr = strpbrk(arg, ";:+@%");
43650656eecSMasami Hiramatsu 	if (ptr) {
43750656eecSMasami Hiramatsu 		nc = *ptr;
43850656eecSMasami Hiramatsu 		*ptr++ = '\0';
43950656eecSMasami Hiramatsu 	}
44050656eecSMasami Hiramatsu 
44102b95dadSMasami Hiramatsu 	tmp = strdup(arg);
44202b95dadSMasami Hiramatsu 	if (tmp == NULL)
44302b95dadSMasami Hiramatsu 		return -ENOMEM;
44402b95dadSMasami Hiramatsu 
44550656eecSMasami Hiramatsu 	/* Check arg is function or file and copy it */
44602b95dadSMasami Hiramatsu 	if (strchr(tmp, '.'))	/* File */
44702b95dadSMasami Hiramatsu 		pp->file = tmp;
44850656eecSMasami Hiramatsu 	else			/* Function */
44902b95dadSMasami Hiramatsu 		pp->function = tmp;
45050656eecSMasami Hiramatsu 
45150656eecSMasami Hiramatsu 	/* Parse other options */
45250656eecSMasami Hiramatsu 	while (ptr) {
45350656eecSMasami Hiramatsu 		arg = ptr;
45450656eecSMasami Hiramatsu 		c = nc;
4552a9c8c36SMasami Hiramatsu 		if (c == ';') {	/* Lazy pattern must be the last part */
45602b95dadSMasami Hiramatsu 			pp->lazy_line = strdup(arg);
45702b95dadSMasami Hiramatsu 			if (pp->lazy_line == NULL)
45802b95dadSMasami Hiramatsu 				return -ENOMEM;
4592a9c8c36SMasami Hiramatsu 			break;
4602a9c8c36SMasami Hiramatsu 		}
4612a9c8c36SMasami Hiramatsu 		ptr = strpbrk(arg, ";:+@%");
46250656eecSMasami Hiramatsu 		if (ptr) {
46350656eecSMasami Hiramatsu 			nc = *ptr;
46450656eecSMasami Hiramatsu 			*ptr++ = '\0';
46550656eecSMasami Hiramatsu 		}
46650656eecSMasami Hiramatsu 		switch (c) {
46750656eecSMasami Hiramatsu 		case ':':	/* Line number */
46850656eecSMasami Hiramatsu 			pp->line = strtoul(arg, &tmp, 0);
469146a1439SMasami Hiramatsu 			if (*tmp != '\0') {
4702a9c8c36SMasami Hiramatsu 				semantic_error("There is non-digit char"
471146a1439SMasami Hiramatsu 					       " in line number.\n");
472146a1439SMasami Hiramatsu 				return -EINVAL;
473146a1439SMasami Hiramatsu 			}
47450656eecSMasami Hiramatsu 			break;
47550656eecSMasami Hiramatsu 		case '+':	/* Byte offset from a symbol */
47650656eecSMasami Hiramatsu 			pp->offset = strtoul(arg, &tmp, 0);
477146a1439SMasami Hiramatsu 			if (*tmp != '\0') {
4782a9c8c36SMasami Hiramatsu 				semantic_error("There is non-digit character"
479146a1439SMasami Hiramatsu 						" in offset.\n");
480146a1439SMasami Hiramatsu 				return -EINVAL;
481146a1439SMasami Hiramatsu 			}
48250656eecSMasami Hiramatsu 			break;
48350656eecSMasami Hiramatsu 		case '@':	/* File name */
484146a1439SMasami Hiramatsu 			if (pp->file) {
485146a1439SMasami Hiramatsu 				semantic_error("SRC@SRC is not allowed.\n");
486146a1439SMasami Hiramatsu 				return -EINVAL;
487146a1439SMasami Hiramatsu 			}
48802b95dadSMasami Hiramatsu 			pp->file = strdup(arg);
48902b95dadSMasami Hiramatsu 			if (pp->file == NULL)
49002b95dadSMasami Hiramatsu 				return -ENOMEM;
49150656eecSMasami Hiramatsu 			break;
49250656eecSMasami Hiramatsu 		case '%':	/* Probe places */
49350656eecSMasami Hiramatsu 			if (strcmp(arg, "return") == 0) {
49450656eecSMasami Hiramatsu 				pp->retprobe = 1;
495146a1439SMasami Hiramatsu 			} else {	/* Others not supported yet */
496146a1439SMasami Hiramatsu 				semantic_error("%%%s is not supported.\n", arg);
497146a1439SMasami Hiramatsu 				return -ENOTSUP;
498146a1439SMasami Hiramatsu 			}
49950656eecSMasami Hiramatsu 			break;
500146a1439SMasami Hiramatsu 		default:	/* Buggy case */
501146a1439SMasami Hiramatsu 			pr_err("This program has a bug at %s:%d.\n",
502146a1439SMasami Hiramatsu 				__FILE__, __LINE__);
503146a1439SMasami Hiramatsu 			return -ENOTSUP;
50450656eecSMasami Hiramatsu 			break;
50550656eecSMasami Hiramatsu 		}
50650656eecSMasami Hiramatsu 	}
50750656eecSMasami Hiramatsu 
50850656eecSMasami Hiramatsu 	/* Exclusion check */
509146a1439SMasami Hiramatsu 	if (pp->lazy_line && pp->line) {
5102a9c8c36SMasami Hiramatsu 		semantic_error("Lazy pattern can't be used with line number.");
511146a1439SMasami Hiramatsu 		return -EINVAL;
512146a1439SMasami Hiramatsu 	}
5132a9c8c36SMasami Hiramatsu 
514146a1439SMasami Hiramatsu 	if (pp->lazy_line && pp->offset) {
5152a9c8c36SMasami Hiramatsu 		semantic_error("Lazy pattern can't be used with offset.");
516146a1439SMasami Hiramatsu 		return -EINVAL;
517146a1439SMasami Hiramatsu 	}
5182a9c8c36SMasami Hiramatsu 
519146a1439SMasami Hiramatsu 	if (pp->line && pp->offset) {
52050656eecSMasami Hiramatsu 		semantic_error("Offset can't be used with line number.");
521146a1439SMasami Hiramatsu 		return -EINVAL;
522146a1439SMasami Hiramatsu 	}
52350656eecSMasami Hiramatsu 
524146a1439SMasami Hiramatsu 	if (!pp->line && !pp->lazy_line && pp->file && !pp->function) {
5252a9c8c36SMasami Hiramatsu 		semantic_error("File always requires line number or "
5262a9c8c36SMasami Hiramatsu 			       "lazy pattern.");
527146a1439SMasami Hiramatsu 		return -EINVAL;
528146a1439SMasami Hiramatsu 	}
52950656eecSMasami Hiramatsu 
530146a1439SMasami Hiramatsu 	if (pp->offset && !pp->function) {
53150656eecSMasami Hiramatsu 		semantic_error("Offset requires an entry function.");
532146a1439SMasami Hiramatsu 		return -EINVAL;
533146a1439SMasami Hiramatsu 	}
53450656eecSMasami Hiramatsu 
535146a1439SMasami Hiramatsu 	if (pp->retprobe && !pp->function) {
53650656eecSMasami Hiramatsu 		semantic_error("Return probe requires an entry function.");
537146a1439SMasami Hiramatsu 		return -EINVAL;
538146a1439SMasami Hiramatsu 	}
53950656eecSMasami Hiramatsu 
540146a1439SMasami Hiramatsu 	if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
5412a9c8c36SMasami Hiramatsu 		semantic_error("Offset/Line/Lazy pattern can't be used with "
5422a9c8c36SMasami Hiramatsu 			       "return probe.");
543146a1439SMasami Hiramatsu 		return -EINVAL;
544146a1439SMasami Hiramatsu 	}
54550656eecSMasami Hiramatsu 
5464235b045SMasami Hiramatsu 	pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
5472a9c8c36SMasami Hiramatsu 		 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
5482a9c8c36SMasami Hiramatsu 		 pp->lazy_line);
549146a1439SMasami Hiramatsu 	return 0;
55050656eecSMasami Hiramatsu }
55150656eecSMasami Hiramatsu 
5527df2f329SMasami Hiramatsu /* Parse perf-probe event argument */
553146a1439SMasami Hiramatsu static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
5547df2f329SMasami Hiramatsu {
55548481938SMasami Hiramatsu 	char *tmp;
5567df2f329SMasami Hiramatsu 	struct perf_probe_arg_field **fieldp;
5577df2f329SMasami Hiramatsu 
5587df2f329SMasami Hiramatsu 	pr_debug("parsing arg: %s into ", str);
5597df2f329SMasami Hiramatsu 
56048481938SMasami Hiramatsu 	tmp = strchr(str, '=');
56148481938SMasami Hiramatsu 	if (tmp) {
56202b95dadSMasami Hiramatsu 		arg->name = strndup(str, tmp - str);
56302b95dadSMasami Hiramatsu 		if (arg->name == NULL)
56402b95dadSMasami Hiramatsu 			return -ENOMEM;
56511a1ca35SMasami Hiramatsu 		pr_debug("name:%s ", arg->name);
56648481938SMasami Hiramatsu 		str = tmp + 1;
56748481938SMasami Hiramatsu 	}
56848481938SMasami Hiramatsu 
56911a1ca35SMasami Hiramatsu 	tmp = strchr(str, ':');
57011a1ca35SMasami Hiramatsu 	if (tmp) {	/* Type setting */
57111a1ca35SMasami Hiramatsu 		*tmp = '\0';
57202b95dadSMasami Hiramatsu 		arg->type = strdup(tmp + 1);
57302b95dadSMasami Hiramatsu 		if (arg->type == NULL)
57402b95dadSMasami Hiramatsu 			return -ENOMEM;
57511a1ca35SMasami Hiramatsu 		pr_debug("type:%s ", arg->type);
57611a1ca35SMasami Hiramatsu 	}
57711a1ca35SMasami Hiramatsu 
5787df2f329SMasami Hiramatsu 	tmp = strpbrk(str, "-.");
5797df2f329SMasami Hiramatsu 	if (!is_c_varname(str) || !tmp) {
5807df2f329SMasami Hiramatsu 		/* A variable, register, symbol or special value */
58102b95dadSMasami Hiramatsu 		arg->var = strdup(str);
58202b95dadSMasami Hiramatsu 		if (arg->var == NULL)
58302b95dadSMasami Hiramatsu 			return -ENOMEM;
58448481938SMasami Hiramatsu 		pr_debug("%s\n", arg->var);
585146a1439SMasami Hiramatsu 		return 0;
5867df2f329SMasami Hiramatsu 	}
5877df2f329SMasami Hiramatsu 
5887df2f329SMasami Hiramatsu 	/* Structure fields */
58902b95dadSMasami Hiramatsu 	arg->var = strndup(str, tmp - str);
59002b95dadSMasami Hiramatsu 	if (arg->var == NULL)
59102b95dadSMasami Hiramatsu 		return -ENOMEM;
59248481938SMasami Hiramatsu 	pr_debug("%s, ", arg->var);
5937df2f329SMasami Hiramatsu 	fieldp = &arg->field;
5947df2f329SMasami Hiramatsu 
5957df2f329SMasami Hiramatsu 	do {
596e334016fSMasami Hiramatsu 		*fieldp = zalloc(sizeof(struct perf_probe_arg_field));
597e334016fSMasami Hiramatsu 		if (*fieldp == NULL)
598e334016fSMasami Hiramatsu 			return -ENOMEM;
5997df2f329SMasami Hiramatsu 		if (*tmp == '.') {
6007df2f329SMasami Hiramatsu 			str = tmp + 1;
6017df2f329SMasami Hiramatsu 			(*fieldp)->ref = false;
6027df2f329SMasami Hiramatsu 		} else if (tmp[1] == '>') {
6037df2f329SMasami Hiramatsu 			str = tmp + 2;
6047df2f329SMasami Hiramatsu 			(*fieldp)->ref = true;
605146a1439SMasami Hiramatsu 		} else {
606146a1439SMasami Hiramatsu 			semantic_error("Argument parse error: %s\n", str);
607146a1439SMasami Hiramatsu 			return -EINVAL;
608146a1439SMasami Hiramatsu 		}
6097df2f329SMasami Hiramatsu 
6107df2f329SMasami Hiramatsu 		tmp = strpbrk(str, "-.");
6117df2f329SMasami Hiramatsu 		if (tmp) {
61202b95dadSMasami Hiramatsu 			(*fieldp)->name = strndup(str, tmp - str);
61302b95dadSMasami Hiramatsu 			if ((*fieldp)->name == NULL)
61402b95dadSMasami Hiramatsu 				return -ENOMEM;
6157df2f329SMasami Hiramatsu 			pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
6167df2f329SMasami Hiramatsu 			fieldp = &(*fieldp)->next;
6177df2f329SMasami Hiramatsu 		}
6187df2f329SMasami Hiramatsu 	} while (tmp);
61902b95dadSMasami Hiramatsu 	(*fieldp)->name = strdup(str);
62002b95dadSMasami Hiramatsu 	if ((*fieldp)->name == NULL)
62102b95dadSMasami Hiramatsu 		return -ENOMEM;
6227df2f329SMasami Hiramatsu 	pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
623df0faf4bSMasami Hiramatsu 
624df0faf4bSMasami Hiramatsu 	/* If no name is specified, set the last field name */
62502b95dadSMasami Hiramatsu 	if (!arg->name) {
62602b95dadSMasami Hiramatsu 		arg->name = strdup((*fieldp)->name);
62702b95dadSMasami Hiramatsu 		if (arg->name == NULL)
62802b95dadSMasami Hiramatsu 			return -ENOMEM;
62902b95dadSMasami Hiramatsu 	}
630146a1439SMasami Hiramatsu 	return 0;
6317df2f329SMasami Hiramatsu }
6327df2f329SMasami Hiramatsu 
6334235b045SMasami Hiramatsu /* Parse perf-probe event command */
634146a1439SMasami Hiramatsu int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
63550656eecSMasami Hiramatsu {
636e1c01d61SMasami Hiramatsu 	char **argv;
637146a1439SMasami Hiramatsu 	int argc, i, ret = 0;
638fac13fd5SMasami Hiramatsu 
6394235b045SMasami Hiramatsu 	argv = argv_split(cmd, &argc);
640146a1439SMasami Hiramatsu 	if (!argv) {
641146a1439SMasami Hiramatsu 		pr_debug("Failed to split arguments.\n");
642146a1439SMasami Hiramatsu 		return -ENOMEM;
643146a1439SMasami Hiramatsu 	}
644146a1439SMasami Hiramatsu 	if (argc - 1 > MAX_PROBE_ARGS) {
645146a1439SMasami Hiramatsu 		semantic_error("Too many probe arguments (%d).\n", argc - 1);
646146a1439SMasami Hiramatsu 		ret = -ERANGE;
647146a1439SMasami Hiramatsu 		goto out;
648146a1439SMasami Hiramatsu 	}
64950656eecSMasami Hiramatsu 	/* Parse probe point */
650146a1439SMasami Hiramatsu 	ret = parse_perf_probe_point(argv[0], pev);
651146a1439SMasami Hiramatsu 	if (ret < 0)
652146a1439SMasami Hiramatsu 		goto out;
65350656eecSMasami Hiramatsu 
654e1c01d61SMasami Hiramatsu 	/* Copy arguments and ensure return probe has no C argument */
6554235b045SMasami Hiramatsu 	pev->nargs = argc - 1;
656e334016fSMasami Hiramatsu 	pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
657e334016fSMasami Hiramatsu 	if (pev->args == NULL) {
658e334016fSMasami Hiramatsu 		ret = -ENOMEM;
659e334016fSMasami Hiramatsu 		goto out;
660e334016fSMasami Hiramatsu 	}
661146a1439SMasami Hiramatsu 	for (i = 0; i < pev->nargs && ret >= 0; i++) {
662146a1439SMasami Hiramatsu 		ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]);
663146a1439SMasami Hiramatsu 		if (ret >= 0 &&
664146a1439SMasami Hiramatsu 		    is_c_varname(pev->args[i].var) && pev->point.retprobe) {
6654235b045SMasami Hiramatsu 			semantic_error("You can't specify local variable for"
666146a1439SMasami Hiramatsu 				       " kretprobe.\n");
667146a1439SMasami Hiramatsu 			ret = -EINVAL;
668e1c01d61SMasami Hiramatsu 		}
669146a1439SMasami Hiramatsu 	}
670146a1439SMasami Hiramatsu out:
671e1c01d61SMasami Hiramatsu 	argv_free(argv);
672146a1439SMasami Hiramatsu 
673146a1439SMasami Hiramatsu 	return ret;
67450656eecSMasami Hiramatsu }
67550656eecSMasami Hiramatsu 
6764235b045SMasami Hiramatsu /* Return true if this perf_probe_event requires debuginfo */
6774235b045SMasami Hiramatsu bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
6784de189feSMasami Hiramatsu {
6794235b045SMasami Hiramatsu 	int i;
6804235b045SMasami Hiramatsu 
6814235b045SMasami Hiramatsu 	if (pev->point.file || pev->point.line || pev->point.lazy_line)
6824235b045SMasami Hiramatsu 		return true;
6834235b045SMasami Hiramatsu 
6844235b045SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++)
68548481938SMasami Hiramatsu 		if (is_c_varname(pev->args[i].var))
6864235b045SMasami Hiramatsu 			return true;
6874235b045SMasami Hiramatsu 
6884235b045SMasami Hiramatsu 	return false;
6894235b045SMasami Hiramatsu }
6904235b045SMasami Hiramatsu 
6914235b045SMasami Hiramatsu /* Parse kprobe_events event into struct probe_point */
692146a1439SMasami Hiramatsu int parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
6934235b045SMasami Hiramatsu {
6944235b045SMasami Hiramatsu 	struct kprobe_trace_point *tp = &tev->point;
6954de189feSMasami Hiramatsu 	char pr;
6964de189feSMasami Hiramatsu 	char *p;
6974de189feSMasami Hiramatsu 	int ret, i, argc;
6984de189feSMasami Hiramatsu 	char **argv;
6994de189feSMasami Hiramatsu 
7004235b045SMasami Hiramatsu 	pr_debug("Parsing kprobe_events: %s\n", cmd);
7014235b045SMasami Hiramatsu 	argv = argv_split(cmd, &argc);
702146a1439SMasami Hiramatsu 	if (!argv) {
703146a1439SMasami Hiramatsu 		pr_debug("Failed to split arguments.\n");
704146a1439SMasami Hiramatsu 		return -ENOMEM;
705146a1439SMasami Hiramatsu 	}
706146a1439SMasami Hiramatsu 	if (argc < 2) {
707146a1439SMasami Hiramatsu 		semantic_error("Too few probe arguments.\n");
708146a1439SMasami Hiramatsu 		ret = -ERANGE;
709146a1439SMasami Hiramatsu 		goto out;
710146a1439SMasami Hiramatsu 	}
7114de189feSMasami Hiramatsu 
7124de189feSMasami Hiramatsu 	/* Scan event and group name. */
71393aaa45aSLiming Wang 	ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
7144235b045SMasami Hiramatsu 		     &pr, (float *)(void *)&tev->group,
7154235b045SMasami Hiramatsu 		     (float *)(void *)&tev->event);
716146a1439SMasami Hiramatsu 	if (ret != 3) {
717146a1439SMasami Hiramatsu 		semantic_error("Failed to parse event name: %s\n", argv[0]);
718146a1439SMasami Hiramatsu 		ret = -EINVAL;
719146a1439SMasami Hiramatsu 		goto out;
720146a1439SMasami Hiramatsu 	}
7214235b045SMasami Hiramatsu 	pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr);
7224de189feSMasami Hiramatsu 
7234235b045SMasami Hiramatsu 	tp->retprobe = (pr == 'r');
7244de189feSMasami Hiramatsu 
7254de189feSMasami Hiramatsu 	/* Scan function name and offset */
7264235b045SMasami Hiramatsu 	ret = sscanf(argv[1], "%a[^+]+%lu", (float *)(void *)&tp->symbol,
7274235b045SMasami Hiramatsu 		     &tp->offset);
7284de189feSMasami Hiramatsu 	if (ret == 1)
7294235b045SMasami Hiramatsu 		tp->offset = 0;
7304de189feSMasami Hiramatsu 
7314235b045SMasami Hiramatsu 	tev->nargs = argc - 2;
732e334016fSMasami Hiramatsu 	tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
733e334016fSMasami Hiramatsu 	if (tev->args == NULL) {
734e334016fSMasami Hiramatsu 		ret = -ENOMEM;
735e334016fSMasami Hiramatsu 		goto out;
736e334016fSMasami Hiramatsu 	}
7374235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
7384de189feSMasami Hiramatsu 		p = strchr(argv[i + 2], '=');
7394de189feSMasami Hiramatsu 		if (p)	/* We don't need which register is assigned. */
7404235b045SMasami Hiramatsu 			*p++ = '\0';
7414235b045SMasami Hiramatsu 		else
7424235b045SMasami Hiramatsu 			p = argv[i + 2];
74302b95dadSMasami Hiramatsu 		tev->args[i].name = strdup(argv[i + 2]);
7444235b045SMasami Hiramatsu 		/* TODO: parse regs and offset */
74502b95dadSMasami Hiramatsu 		tev->args[i].value = strdup(p);
74602b95dadSMasami Hiramatsu 		if (tev->args[i].name == NULL || tev->args[i].value == NULL) {
74702b95dadSMasami Hiramatsu 			ret = -ENOMEM;
74802b95dadSMasami Hiramatsu 			goto out;
74902b95dadSMasami Hiramatsu 		}
7504de189feSMasami Hiramatsu 	}
751146a1439SMasami Hiramatsu 	ret = 0;
752146a1439SMasami Hiramatsu out:
7534de189feSMasami Hiramatsu 	argv_free(argv);
754146a1439SMasami Hiramatsu 	return ret;
7554de189feSMasami Hiramatsu }
7564de189feSMasami Hiramatsu 
7577df2f329SMasami Hiramatsu /* Compose only probe arg */
7587df2f329SMasami Hiramatsu int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
7597df2f329SMasami Hiramatsu {
7607df2f329SMasami Hiramatsu 	struct perf_probe_arg_field *field = pa->field;
7617df2f329SMasami Hiramatsu 	int ret;
7627df2f329SMasami Hiramatsu 	char *tmp = buf;
7637df2f329SMasami Hiramatsu 
76448481938SMasami Hiramatsu 	if (pa->name && pa->var)
76548481938SMasami Hiramatsu 		ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var);
76648481938SMasami Hiramatsu 	else
76748481938SMasami Hiramatsu 		ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var);
7687df2f329SMasami Hiramatsu 	if (ret <= 0)
7697df2f329SMasami Hiramatsu 		goto error;
7707df2f329SMasami Hiramatsu 	tmp += ret;
7717df2f329SMasami Hiramatsu 	len -= ret;
7727df2f329SMasami Hiramatsu 
7737df2f329SMasami Hiramatsu 	while (field) {
7747df2f329SMasami Hiramatsu 		ret = e_snprintf(tmp, len, "%s%s", field->ref ? "->" : ".",
7757df2f329SMasami Hiramatsu 				 field->name);
7767df2f329SMasami Hiramatsu 		if (ret <= 0)
7777df2f329SMasami Hiramatsu 			goto error;
7787df2f329SMasami Hiramatsu 		tmp += ret;
7797df2f329SMasami Hiramatsu 		len -= ret;
7807df2f329SMasami Hiramatsu 		field = field->next;
7817df2f329SMasami Hiramatsu 	}
78211a1ca35SMasami Hiramatsu 
78311a1ca35SMasami Hiramatsu 	if (pa->type) {
78411a1ca35SMasami Hiramatsu 		ret = e_snprintf(tmp, len, ":%s", pa->type);
78511a1ca35SMasami Hiramatsu 		if (ret <= 0)
78611a1ca35SMasami Hiramatsu 			goto error;
78711a1ca35SMasami Hiramatsu 		tmp += ret;
78811a1ca35SMasami Hiramatsu 		len -= ret;
78911a1ca35SMasami Hiramatsu 	}
79011a1ca35SMasami Hiramatsu 
7917df2f329SMasami Hiramatsu 	return tmp - buf;
7927df2f329SMasami Hiramatsu error:
793146a1439SMasami Hiramatsu 	pr_debug("Failed to synthesize perf probe argument: %s",
794146a1439SMasami Hiramatsu 		 strerror(-ret));
795146a1439SMasami Hiramatsu 	return ret;
7967df2f329SMasami Hiramatsu }
7977df2f329SMasami Hiramatsu 
7984235b045SMasami Hiramatsu /* Compose only probe point (not argument) */
7994235b045SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
80050656eecSMasami Hiramatsu {
801fb1587d8SMasami Hiramatsu 	char *buf, *tmp;
802fb1587d8SMasami Hiramatsu 	char offs[32] = "", line[32] = "", file[32] = "";
803fb1587d8SMasami Hiramatsu 	int ret, len;
80450656eecSMasami Hiramatsu 
805e334016fSMasami Hiramatsu 	buf = zalloc(MAX_CMDLEN);
806e334016fSMasami Hiramatsu 	if (buf == NULL) {
807e334016fSMasami Hiramatsu 		ret = -ENOMEM;
808e334016fSMasami Hiramatsu 		goto error;
809e334016fSMasami Hiramatsu 	}
8104de189feSMasami Hiramatsu 	if (pp->offset) {
811fb1587d8SMasami Hiramatsu 		ret = e_snprintf(offs, 32, "+%lu", pp->offset);
8124de189feSMasami Hiramatsu 		if (ret <= 0)
8134de189feSMasami Hiramatsu 			goto error;
8144de189feSMasami Hiramatsu 	}
8154de189feSMasami Hiramatsu 	if (pp->line) {
816fb1587d8SMasami Hiramatsu 		ret = e_snprintf(line, 32, ":%d", pp->line);
817fb1587d8SMasami Hiramatsu 		if (ret <= 0)
818fb1587d8SMasami Hiramatsu 			goto error;
819fb1587d8SMasami Hiramatsu 	}
820fb1587d8SMasami Hiramatsu 	if (pp->file) {
821dd259c5dSMasami Hiramatsu 		len = strlen(pp->file) - 31;
822fb1587d8SMasami Hiramatsu 		if (len < 0)
823fb1587d8SMasami Hiramatsu 			len = 0;
824fb1587d8SMasami Hiramatsu 		tmp = strchr(pp->file + len, '/');
825fb1587d8SMasami Hiramatsu 		if (!tmp)
826dd259c5dSMasami Hiramatsu 			tmp = pp->file + len;
827fb1587d8SMasami Hiramatsu 		ret = e_snprintf(file, 32, "@%s", tmp + 1);
8284de189feSMasami Hiramatsu 		if (ret <= 0)
8294de189feSMasami Hiramatsu 			goto error;
8304de189feSMasami Hiramatsu 	}
8314de189feSMasami Hiramatsu 
8324de189feSMasami Hiramatsu 	if (pp->function)
833fb1587d8SMasami Hiramatsu 		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function,
834fb1587d8SMasami Hiramatsu 				 offs, pp->retprobe ? "%return" : "", line,
835fb1587d8SMasami Hiramatsu 				 file);
8364de189feSMasami Hiramatsu 	else
837fb1587d8SMasami Hiramatsu 		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line);
8384235b045SMasami Hiramatsu 	if (ret <= 0)
8394235b045SMasami Hiramatsu 		goto error;
8404235b045SMasami Hiramatsu 
8414235b045SMasami Hiramatsu 	return buf;
8424235b045SMasami Hiramatsu error:
843146a1439SMasami Hiramatsu 	pr_debug("Failed to synthesize perf probe point: %s",
844146a1439SMasami Hiramatsu 		 strerror(-ret));
845e334016fSMasami Hiramatsu 	if (buf)
846146a1439SMasami Hiramatsu 		free(buf);
847146a1439SMasami Hiramatsu 	return NULL;
8484235b045SMasami Hiramatsu }
8494235b045SMasami Hiramatsu 
8504235b045SMasami Hiramatsu #if 0
8514235b045SMasami Hiramatsu char *synthesize_perf_probe_command(struct perf_probe_event *pev)
8524235b045SMasami Hiramatsu {
8534235b045SMasami Hiramatsu 	char *buf;
8544235b045SMasami Hiramatsu 	int i, len, ret;
8554235b045SMasami Hiramatsu 
8564235b045SMasami Hiramatsu 	buf = synthesize_perf_probe_point(&pev->point);
8574235b045SMasami Hiramatsu 	if (!buf)
8584235b045SMasami Hiramatsu 		return NULL;
8594235b045SMasami Hiramatsu 
8604235b045SMasami Hiramatsu 	len = strlen(buf);
8614235b045SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++) {
8624235b045SMasami Hiramatsu 		ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
8634235b045SMasami Hiramatsu 				 pev->args[i].name);
8647ef17aafSMasami Hiramatsu 		if (ret <= 0) {
8654235b045SMasami Hiramatsu 			free(buf);
8664235b045SMasami Hiramatsu 			return NULL;
8677ef17aafSMasami Hiramatsu 		}
8684235b045SMasami Hiramatsu 		len += ret;
8697ef17aafSMasami Hiramatsu 	}
87050656eecSMasami Hiramatsu 
8714235b045SMasami Hiramatsu 	return buf;
8724235b045SMasami Hiramatsu }
8734235b045SMasami Hiramatsu #endif
8744235b045SMasami Hiramatsu 
8754235b045SMasami Hiramatsu static int __synthesize_kprobe_trace_arg_ref(struct kprobe_trace_arg_ref *ref,
8764235b045SMasami Hiramatsu 					     char **buf, size_t *buflen,
8774235b045SMasami Hiramatsu 					     int depth)
8787ef17aafSMasami Hiramatsu {
8794235b045SMasami Hiramatsu 	int ret;
8804235b045SMasami Hiramatsu 	if (ref->next) {
8814235b045SMasami Hiramatsu 		depth = __synthesize_kprobe_trace_arg_ref(ref->next, buf,
8824235b045SMasami Hiramatsu 							 buflen, depth + 1);
8834235b045SMasami Hiramatsu 		if (depth < 0)
8844235b045SMasami Hiramatsu 			goto out;
8854235b045SMasami Hiramatsu 	}
8864235b045SMasami Hiramatsu 
8874235b045SMasami Hiramatsu 	ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset);
8884235b045SMasami Hiramatsu 	if (ret < 0)
8894235b045SMasami Hiramatsu 		depth = ret;
8904235b045SMasami Hiramatsu 	else {
8914235b045SMasami Hiramatsu 		*buf += ret;
8924235b045SMasami Hiramatsu 		*buflen -= ret;
8934235b045SMasami Hiramatsu 	}
8944235b045SMasami Hiramatsu out:
8954235b045SMasami Hiramatsu 	return depth;
8964235b045SMasami Hiramatsu 
8974235b045SMasami Hiramatsu }
8984235b045SMasami Hiramatsu 
8994235b045SMasami Hiramatsu static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
9004235b045SMasami Hiramatsu 				       char *buf, size_t buflen)
9014235b045SMasami Hiramatsu {
9024235b045SMasami Hiramatsu 	int ret, depth = 0;
9034235b045SMasami Hiramatsu 	char *tmp = buf;
9044235b045SMasami Hiramatsu 
9054235b045SMasami Hiramatsu 	/* Argument name or separator */
9064235b045SMasami Hiramatsu 	if (arg->name)
9074235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, " %s=", arg->name);
9084235b045SMasami Hiramatsu 	else
9094235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, " ");
9104235b045SMasami Hiramatsu 	if (ret < 0)
9114235b045SMasami Hiramatsu 		return ret;
9124235b045SMasami Hiramatsu 	buf += ret;
9134235b045SMasami Hiramatsu 	buflen -= ret;
9144235b045SMasami Hiramatsu 
9154235b045SMasami Hiramatsu 	/* Dereferencing arguments */
9164235b045SMasami Hiramatsu 	if (arg->ref) {
9174235b045SMasami Hiramatsu 		depth = __synthesize_kprobe_trace_arg_ref(arg->ref, &buf,
9184235b045SMasami Hiramatsu 							  &buflen, 1);
9194235b045SMasami Hiramatsu 		if (depth < 0)
9204235b045SMasami Hiramatsu 			return depth;
9214235b045SMasami Hiramatsu 	}
9224235b045SMasami Hiramatsu 
9234235b045SMasami Hiramatsu 	/* Print argument value */
9244235b045SMasami Hiramatsu 	ret = e_snprintf(buf, buflen, "%s", arg->value);
9254235b045SMasami Hiramatsu 	if (ret < 0)
9264235b045SMasami Hiramatsu 		return ret;
9274235b045SMasami Hiramatsu 	buf += ret;
9284235b045SMasami Hiramatsu 	buflen -= ret;
9294235b045SMasami Hiramatsu 
9304235b045SMasami Hiramatsu 	/* Closing */
9314235b045SMasami Hiramatsu 	while (depth--) {
9324235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, ")");
9334235b045SMasami Hiramatsu 		if (ret < 0)
9344235b045SMasami Hiramatsu 			return ret;
9354235b045SMasami Hiramatsu 		buf += ret;
9364235b045SMasami Hiramatsu 		buflen -= ret;
9374235b045SMasami Hiramatsu 	}
9384984912eSMasami Hiramatsu 	/* Print argument type */
9394984912eSMasami Hiramatsu 	if (arg->type) {
9404984912eSMasami Hiramatsu 		ret = e_snprintf(buf, buflen, ":%s", arg->type);
9414984912eSMasami Hiramatsu 		if (ret <= 0)
9424984912eSMasami Hiramatsu 			return ret;
9434984912eSMasami Hiramatsu 		buf += ret;
9444984912eSMasami Hiramatsu 	}
9454235b045SMasami Hiramatsu 
9464235b045SMasami Hiramatsu 	return buf - tmp;
9474235b045SMasami Hiramatsu }
9484235b045SMasami Hiramatsu 
9494235b045SMasami Hiramatsu char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev)
9504235b045SMasami Hiramatsu {
9514235b045SMasami Hiramatsu 	struct kprobe_trace_point *tp = &tev->point;
9527ef17aafSMasami Hiramatsu 	char *buf;
9537ef17aafSMasami Hiramatsu 	int i, len, ret;
9547ef17aafSMasami Hiramatsu 
955e334016fSMasami Hiramatsu 	buf = zalloc(MAX_CMDLEN);
956e334016fSMasami Hiramatsu 	if (buf == NULL)
957e334016fSMasami Hiramatsu 		return NULL;
958e334016fSMasami Hiramatsu 
9594235b045SMasami Hiramatsu 	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu",
9604235b045SMasami Hiramatsu 			 tp->retprobe ? 'r' : 'p',
9614235b045SMasami Hiramatsu 			 tev->group, tev->event,
9624235b045SMasami Hiramatsu 			 tp->symbol, tp->offset);
9634235b045SMasami Hiramatsu 	if (len <= 0)
9644235b045SMasami Hiramatsu 		goto error;
9657ef17aafSMasami Hiramatsu 
9664235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
9674235b045SMasami Hiramatsu 		ret = synthesize_kprobe_trace_arg(&tev->args[i], buf + len,
9684235b045SMasami Hiramatsu 						  MAX_CMDLEN - len);
9694de189feSMasami Hiramatsu 		if (ret <= 0)
97050656eecSMasami Hiramatsu 			goto error;
97150656eecSMasami Hiramatsu 		len += ret;
97250656eecSMasami Hiramatsu 	}
97350656eecSMasami Hiramatsu 
9744235b045SMasami Hiramatsu 	return buf;
97550656eecSMasami Hiramatsu error:
9764235b045SMasami Hiramatsu 	free(buf);
9774235b045SMasami Hiramatsu 	return NULL;
97850656eecSMasami Hiramatsu }
97950656eecSMasami Hiramatsu 
980146a1439SMasami Hiramatsu int convert_to_perf_probe_event(struct kprobe_trace_event *tev,
9814235b045SMasami Hiramatsu 				struct perf_probe_event *pev)
9824de189feSMasami Hiramatsu {
98302b95dadSMasami Hiramatsu 	char buf[64] = "";
984146a1439SMasami Hiramatsu 	int i, ret;
9854de189feSMasami Hiramatsu 
9864b4da7f7SMasami Hiramatsu 	/* Convert event/group name */
98702b95dadSMasami Hiramatsu 	pev->event = strdup(tev->event);
98802b95dadSMasami Hiramatsu 	pev->group = strdup(tev->group);
98902b95dadSMasami Hiramatsu 	if (pev->event == NULL || pev->group == NULL)
99002b95dadSMasami Hiramatsu 		return -ENOMEM;
991fb1587d8SMasami Hiramatsu 
9924b4da7f7SMasami Hiramatsu 	/* Convert trace_point to probe_point */
993146a1439SMasami Hiramatsu 	ret = convert_to_perf_probe_point(&tev->point, &pev->point);
994146a1439SMasami Hiramatsu 	if (ret < 0)
995146a1439SMasami Hiramatsu 		return ret;
9964b4da7f7SMasami Hiramatsu 
9974235b045SMasami Hiramatsu 	/* Convert trace_arg to probe_arg */
9984235b045SMasami Hiramatsu 	pev->nargs = tev->nargs;
999e334016fSMasami Hiramatsu 	pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
1000e334016fSMasami Hiramatsu 	if (pev->args == NULL)
1001e334016fSMasami Hiramatsu 		return -ENOMEM;
100202b95dadSMasami Hiramatsu 	for (i = 0; i < tev->nargs && ret >= 0; i++) {
10034235b045SMasami Hiramatsu 		if (tev->args[i].name)
100402b95dadSMasami Hiramatsu 			pev->args[i].name = strdup(tev->args[i].name);
10054235b045SMasami Hiramatsu 		else {
1006146a1439SMasami Hiramatsu 			ret = synthesize_kprobe_trace_arg(&tev->args[i],
1007146a1439SMasami Hiramatsu 							  buf, 64);
100802b95dadSMasami Hiramatsu 			pev->args[i].name = strdup(buf);
100902b95dadSMasami Hiramatsu 		}
101002b95dadSMasami Hiramatsu 		if (pev->args[i].name == NULL && ret >= 0)
101102b95dadSMasami Hiramatsu 			ret = -ENOMEM;
10124de189feSMasami Hiramatsu 	}
1013146a1439SMasami Hiramatsu 
1014146a1439SMasami Hiramatsu 	if (ret < 0)
1015146a1439SMasami Hiramatsu 		clear_perf_probe_event(pev);
1016146a1439SMasami Hiramatsu 
1017146a1439SMasami Hiramatsu 	return ret;
10184235b045SMasami Hiramatsu }
10194de189feSMasami Hiramatsu 
10204235b045SMasami Hiramatsu void clear_perf_probe_event(struct perf_probe_event *pev)
10214235b045SMasami Hiramatsu {
10224235b045SMasami Hiramatsu 	struct perf_probe_point *pp = &pev->point;
10237df2f329SMasami Hiramatsu 	struct perf_probe_arg_field *field, *next;
10244235b045SMasami Hiramatsu 	int i;
10254de189feSMasami Hiramatsu 
10264235b045SMasami Hiramatsu 	if (pev->event)
10274235b045SMasami Hiramatsu 		free(pev->event);
10284235b045SMasami Hiramatsu 	if (pev->group)
10294235b045SMasami Hiramatsu 		free(pev->group);
10304235b045SMasami Hiramatsu 	if (pp->file)
10314235b045SMasami Hiramatsu 		free(pp->file);
10324235b045SMasami Hiramatsu 	if (pp->function)
10334235b045SMasami Hiramatsu 		free(pp->function);
10344235b045SMasami Hiramatsu 	if (pp->lazy_line)
10354235b045SMasami Hiramatsu 		free(pp->lazy_line);
10367df2f329SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++) {
10374235b045SMasami Hiramatsu 		if (pev->args[i].name)
10384235b045SMasami Hiramatsu 			free(pev->args[i].name);
103948481938SMasami Hiramatsu 		if (pev->args[i].var)
104048481938SMasami Hiramatsu 			free(pev->args[i].var);
104111a1ca35SMasami Hiramatsu 		if (pev->args[i].type)
104211a1ca35SMasami Hiramatsu 			free(pev->args[i].type);
10437df2f329SMasami Hiramatsu 		field = pev->args[i].field;
10447df2f329SMasami Hiramatsu 		while (field) {
10457df2f329SMasami Hiramatsu 			next = field->next;
10467df2f329SMasami Hiramatsu 			if (field->name)
10477df2f329SMasami Hiramatsu 				free(field->name);
10487df2f329SMasami Hiramatsu 			free(field);
10497df2f329SMasami Hiramatsu 			field = next;
10507df2f329SMasami Hiramatsu 		}
10517df2f329SMasami Hiramatsu 	}
10524235b045SMasami Hiramatsu 	if (pev->args)
10534235b045SMasami Hiramatsu 		free(pev->args);
10544235b045SMasami Hiramatsu 	memset(pev, 0, sizeof(*pev));
10554235b045SMasami Hiramatsu }
10564235b045SMasami Hiramatsu 
10574235b045SMasami Hiramatsu void clear_kprobe_trace_event(struct kprobe_trace_event *tev)
10584235b045SMasami Hiramatsu {
10594235b045SMasami Hiramatsu 	struct kprobe_trace_arg_ref *ref, *next;
10604235b045SMasami Hiramatsu 	int i;
10614235b045SMasami Hiramatsu 
10624235b045SMasami Hiramatsu 	if (tev->event)
10634235b045SMasami Hiramatsu 		free(tev->event);
10644235b045SMasami Hiramatsu 	if (tev->group)
10654235b045SMasami Hiramatsu 		free(tev->group);
10664235b045SMasami Hiramatsu 	if (tev->point.symbol)
10674235b045SMasami Hiramatsu 		free(tev->point.symbol);
10684235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
10694235b045SMasami Hiramatsu 		if (tev->args[i].name)
10704235b045SMasami Hiramatsu 			free(tev->args[i].name);
10714235b045SMasami Hiramatsu 		if (tev->args[i].value)
10724235b045SMasami Hiramatsu 			free(tev->args[i].value);
10734984912eSMasami Hiramatsu 		if (tev->args[i].type)
10744984912eSMasami Hiramatsu 			free(tev->args[i].type);
10754235b045SMasami Hiramatsu 		ref = tev->args[i].ref;
10764235b045SMasami Hiramatsu 		while (ref) {
10774235b045SMasami Hiramatsu 			next = ref->next;
10784235b045SMasami Hiramatsu 			free(ref);
10794235b045SMasami Hiramatsu 			ref = next;
10804235b045SMasami Hiramatsu 		}
10814235b045SMasami Hiramatsu 	}
10824235b045SMasami Hiramatsu 	if (tev->args)
10834235b045SMasami Hiramatsu 		free(tev->args);
10844235b045SMasami Hiramatsu 	memset(tev, 0, sizeof(*tev));
10854de189feSMasami Hiramatsu }
10864de189feSMasami Hiramatsu 
1087f4d7da49SMasami Hiramatsu static int open_kprobe_events(bool readwrite)
10884de189feSMasami Hiramatsu {
10894de189feSMasami Hiramatsu 	char buf[PATH_MAX];
10907ca5989dSMasami Hiramatsu 	const char *__debugfs;
10914de189feSMasami Hiramatsu 	int ret;
10924de189feSMasami Hiramatsu 
10937ca5989dSMasami Hiramatsu 	__debugfs = debugfs_find_mountpoint();
10947ca5989dSMasami Hiramatsu 	if (__debugfs == NULL) {
10957ca5989dSMasami Hiramatsu 		pr_warning("Debugfs is not mounted.\n");
10967ca5989dSMasami Hiramatsu 		return -ENOENT;
10977ca5989dSMasami Hiramatsu 	}
10987ca5989dSMasami Hiramatsu 
10997ca5989dSMasami Hiramatsu 	ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs);
1100146a1439SMasami Hiramatsu 	if (ret >= 0) {
11017ca5989dSMasami Hiramatsu 		pr_debug("Opening %s write=%d\n", buf, readwrite);
1102f4d7da49SMasami Hiramatsu 		if (readwrite && !probe_event_dry_run)
1103f4d7da49SMasami Hiramatsu 			ret = open(buf, O_RDWR, O_APPEND);
1104f4d7da49SMasami Hiramatsu 		else
1105f4d7da49SMasami Hiramatsu 			ret = open(buf, O_RDONLY, 0);
1106146a1439SMasami Hiramatsu 	}
1107f4d7da49SMasami Hiramatsu 
11084de189feSMasami Hiramatsu 	if (ret < 0) {
11094de189feSMasami Hiramatsu 		if (errno == ENOENT)
1110146a1439SMasami Hiramatsu 			pr_warning("kprobe_events file does not exist - please"
1111146a1439SMasami Hiramatsu 				 " rebuild kernel with CONFIG_KPROBE_EVENT.\n");
11124de189feSMasami Hiramatsu 		else
1113146a1439SMasami Hiramatsu 			pr_warning("Failed to open kprobe_events file: %s\n",
11144de189feSMasami Hiramatsu 				   strerror(errno));
11154de189feSMasami Hiramatsu 	}
11164de189feSMasami Hiramatsu 	return ret;
11174de189feSMasami Hiramatsu }
11184de189feSMasami Hiramatsu 
11194de189feSMasami Hiramatsu /* Get raw string list of current kprobe_events */
11204235b045SMasami Hiramatsu static struct strlist *get_kprobe_trace_command_rawlist(int fd)
11214de189feSMasami Hiramatsu {
11224de189feSMasami Hiramatsu 	int ret, idx;
11234de189feSMasami Hiramatsu 	FILE *fp;
11244de189feSMasami Hiramatsu 	char buf[MAX_CMDLEN];
11254de189feSMasami Hiramatsu 	char *p;
11264de189feSMasami Hiramatsu 	struct strlist *sl;
11274de189feSMasami Hiramatsu 
11284de189feSMasami Hiramatsu 	sl = strlist__new(true, NULL);
11294de189feSMasami Hiramatsu 
11304de189feSMasami Hiramatsu 	fp = fdopen(dup(fd), "r");
11314de189feSMasami Hiramatsu 	while (!feof(fp)) {
11324de189feSMasami Hiramatsu 		p = fgets(buf, MAX_CMDLEN, fp);
11334de189feSMasami Hiramatsu 		if (!p)
11344de189feSMasami Hiramatsu 			break;
11354de189feSMasami Hiramatsu 
11364de189feSMasami Hiramatsu 		idx = strlen(p) - 1;
11374de189feSMasami Hiramatsu 		if (p[idx] == '\n')
11384de189feSMasami Hiramatsu 			p[idx] = '\0';
11394de189feSMasami Hiramatsu 		ret = strlist__add(sl, buf);
1140146a1439SMasami Hiramatsu 		if (ret < 0) {
1141146a1439SMasami Hiramatsu 			pr_debug("strlist__add failed: %s\n", strerror(-ret));
1142146a1439SMasami Hiramatsu 			strlist__delete(sl);
1143146a1439SMasami Hiramatsu 			return NULL;
1144146a1439SMasami Hiramatsu 		}
11454de189feSMasami Hiramatsu 	}
11464de189feSMasami Hiramatsu 	fclose(fp);
11474de189feSMasami Hiramatsu 
11484de189feSMasami Hiramatsu 	return sl;
11494de189feSMasami Hiramatsu }
11504de189feSMasami Hiramatsu 
1151278498d4SMasami Hiramatsu /* Show an event */
1152146a1439SMasami Hiramatsu static int show_perf_probe_event(struct perf_probe_event *pev)
1153278498d4SMasami Hiramatsu {
11547e990a51SMasami Hiramatsu 	int i, ret;
1155278498d4SMasami Hiramatsu 	char buf[128];
11564235b045SMasami Hiramatsu 	char *place;
1157278498d4SMasami Hiramatsu 
11584235b045SMasami Hiramatsu 	/* Synthesize only event probe point */
11594235b045SMasami Hiramatsu 	place = synthesize_perf_probe_point(&pev->point);
1160146a1439SMasami Hiramatsu 	if (!place)
1161146a1439SMasami Hiramatsu 		return -EINVAL;
11624235b045SMasami Hiramatsu 
11634235b045SMasami Hiramatsu 	ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event);
11647e990a51SMasami Hiramatsu 	if (ret < 0)
1165146a1439SMasami Hiramatsu 		return ret;
1166146a1439SMasami Hiramatsu 
1167fb1587d8SMasami Hiramatsu 	printf("  %-20s (on %s", buf, place);
1168278498d4SMasami Hiramatsu 
11694235b045SMasami Hiramatsu 	if (pev->nargs > 0) {
1170278498d4SMasami Hiramatsu 		printf(" with");
11717df2f329SMasami Hiramatsu 		for (i = 0; i < pev->nargs; i++) {
1172146a1439SMasami Hiramatsu 			ret = synthesize_perf_probe_arg(&pev->args[i],
1173146a1439SMasami Hiramatsu 							buf, 128);
1174146a1439SMasami Hiramatsu 			if (ret < 0)
1175146a1439SMasami Hiramatsu 				break;
11767df2f329SMasami Hiramatsu 			printf(" %s", buf);
11777df2f329SMasami Hiramatsu 		}
1178278498d4SMasami Hiramatsu 	}
1179278498d4SMasami Hiramatsu 	printf(")\n");
11804235b045SMasami Hiramatsu 	free(place);
1181146a1439SMasami Hiramatsu 	return ret;
1182278498d4SMasami Hiramatsu }
1183278498d4SMasami Hiramatsu 
11844de189feSMasami Hiramatsu /* List up current perf-probe events */
1185146a1439SMasami Hiramatsu int show_perf_probe_events(void)
11864de189feSMasami Hiramatsu {
1187146a1439SMasami Hiramatsu 	int fd, ret;
11884235b045SMasami Hiramatsu 	struct kprobe_trace_event tev;
11894235b045SMasami Hiramatsu 	struct perf_probe_event pev;
11904de189feSMasami Hiramatsu 	struct strlist *rawlist;
11914de189feSMasami Hiramatsu 	struct str_node *ent;
11924de189feSMasami Hiramatsu 
119372041334SMasami Hiramatsu 	setup_pager();
1194146a1439SMasami Hiramatsu 	ret = init_vmlinux();
1195146a1439SMasami Hiramatsu 	if (ret < 0)
1196146a1439SMasami Hiramatsu 		return ret;
11974235b045SMasami Hiramatsu 
11984235b045SMasami Hiramatsu 	memset(&tev, 0, sizeof(tev));
11994235b045SMasami Hiramatsu 	memset(&pev, 0, sizeof(pev));
120072041334SMasami Hiramatsu 
1201f4d7da49SMasami Hiramatsu 	fd = open_kprobe_events(false);
1202146a1439SMasami Hiramatsu 	if (fd < 0)
1203146a1439SMasami Hiramatsu 		return fd;
1204146a1439SMasami Hiramatsu 
12054235b045SMasami Hiramatsu 	rawlist = get_kprobe_trace_command_rawlist(fd);
12064de189feSMasami Hiramatsu 	close(fd);
1207146a1439SMasami Hiramatsu 	if (!rawlist)
1208146a1439SMasami Hiramatsu 		return -ENOENT;
12094de189feSMasami Hiramatsu 
1210adf365f4SMasami Hiramatsu 	strlist__for_each(ent, rawlist) {
1211146a1439SMasami Hiramatsu 		ret = parse_kprobe_trace_command(ent->s, &tev);
1212146a1439SMasami Hiramatsu 		if (ret >= 0) {
1213146a1439SMasami Hiramatsu 			ret = convert_to_perf_probe_event(&tev, &pev);
1214146a1439SMasami Hiramatsu 			if (ret >= 0)
1215146a1439SMasami Hiramatsu 				ret = show_perf_probe_event(&pev);
1216146a1439SMasami Hiramatsu 		}
12174235b045SMasami Hiramatsu 		clear_perf_probe_event(&pev);
12184235b045SMasami Hiramatsu 		clear_kprobe_trace_event(&tev);
1219146a1439SMasami Hiramatsu 		if (ret < 0)
1220146a1439SMasami Hiramatsu 			break;
12214de189feSMasami Hiramatsu 	}
12224de189feSMasami Hiramatsu 	strlist__delete(rawlist);
1223146a1439SMasami Hiramatsu 
1224146a1439SMasami Hiramatsu 	return ret;
12254de189feSMasami Hiramatsu }
12264de189feSMasami Hiramatsu 
1227b498ce1fSMasami Hiramatsu /* Get current perf-probe event names */
12284235b045SMasami Hiramatsu static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group)
1229b498ce1fSMasami Hiramatsu {
1230fa28244dSMasami Hiramatsu 	char buf[128];
1231b498ce1fSMasami Hiramatsu 	struct strlist *sl, *rawlist;
1232b498ce1fSMasami Hiramatsu 	struct str_node *ent;
12334235b045SMasami Hiramatsu 	struct kprobe_trace_event tev;
1234146a1439SMasami Hiramatsu 	int ret = 0;
1235b498ce1fSMasami Hiramatsu 
12364235b045SMasami Hiramatsu 	memset(&tev, 0, sizeof(tev));
1237b498ce1fSMasami Hiramatsu 
12384235b045SMasami Hiramatsu 	rawlist = get_kprobe_trace_command_rawlist(fd);
1239e1d2017bSMasami Hiramatsu 	sl = strlist__new(true, NULL);
1240adf365f4SMasami Hiramatsu 	strlist__for_each(ent, rawlist) {
1241146a1439SMasami Hiramatsu 		ret = parse_kprobe_trace_command(ent->s, &tev);
1242146a1439SMasami Hiramatsu 		if (ret < 0)
1243146a1439SMasami Hiramatsu 			break;
1244fa28244dSMasami Hiramatsu 		if (include_group) {
1245146a1439SMasami Hiramatsu 			ret = e_snprintf(buf, 128, "%s:%s", tev.group,
1246146a1439SMasami Hiramatsu 					tev.event);
1247146a1439SMasami Hiramatsu 			if (ret >= 0)
1248146a1439SMasami Hiramatsu 				ret = strlist__add(sl, buf);
1249fa28244dSMasami Hiramatsu 		} else
1250146a1439SMasami Hiramatsu 			ret = strlist__add(sl, tev.event);
12514235b045SMasami Hiramatsu 		clear_kprobe_trace_event(&tev);
1252146a1439SMasami Hiramatsu 		if (ret < 0)
1253146a1439SMasami Hiramatsu 			break;
1254b498ce1fSMasami Hiramatsu 	}
1255b498ce1fSMasami Hiramatsu 	strlist__delete(rawlist);
1256b498ce1fSMasami Hiramatsu 
1257146a1439SMasami Hiramatsu 	if (ret < 0) {
1258146a1439SMasami Hiramatsu 		strlist__delete(sl);
1259146a1439SMasami Hiramatsu 		return NULL;
1260146a1439SMasami Hiramatsu 	}
1261b498ce1fSMasami Hiramatsu 	return sl;
1262b498ce1fSMasami Hiramatsu }
1263b498ce1fSMasami Hiramatsu 
1264146a1439SMasami Hiramatsu static int write_kprobe_trace_event(int fd, struct kprobe_trace_event *tev)
126550656eecSMasami Hiramatsu {
1266*6eca8cc3SFrederic Weisbecker 	int ret = 0;
12674235b045SMasami Hiramatsu 	char *buf = synthesize_kprobe_trace_command(tev);
126850656eecSMasami Hiramatsu 
1269146a1439SMasami Hiramatsu 	if (!buf) {
1270146a1439SMasami Hiramatsu 		pr_debug("Failed to synthesize kprobe trace event.\n");
1271146a1439SMasami Hiramatsu 		return -EINVAL;
1272146a1439SMasami Hiramatsu 	}
1273146a1439SMasami Hiramatsu 
1274fa28244dSMasami Hiramatsu 	pr_debug("Writing event: %s\n", buf);
1275f4d7da49SMasami Hiramatsu 	if (!probe_event_dry_run) {
127650656eecSMasami Hiramatsu 		ret = write(fd, buf, strlen(buf));
127750656eecSMasami Hiramatsu 		if (ret <= 0)
1278146a1439SMasami Hiramatsu 			pr_warning("Failed to write event: %s\n",
1279146a1439SMasami Hiramatsu 				   strerror(errno));
128050656eecSMasami Hiramatsu 	}
12814235b045SMasami Hiramatsu 	free(buf);
1282146a1439SMasami Hiramatsu 	return ret;
1283f4d7da49SMasami Hiramatsu }
128450656eecSMasami Hiramatsu 
1285146a1439SMasami Hiramatsu static int get_new_event_name(char *buf, size_t len, const char *base,
1286d761b08bSMasami Hiramatsu 			      struct strlist *namelist, bool allow_suffix)
1287b498ce1fSMasami Hiramatsu {
1288b498ce1fSMasami Hiramatsu 	int i, ret;
128917f88fcdSMasami Hiramatsu 
129017f88fcdSMasami Hiramatsu 	/* Try no suffix */
129117f88fcdSMasami Hiramatsu 	ret = e_snprintf(buf, len, "%s", base);
1292146a1439SMasami Hiramatsu 	if (ret < 0) {
1293146a1439SMasami Hiramatsu 		pr_debug("snprintf() failed: %s\n", strerror(-ret));
1294146a1439SMasami Hiramatsu 		return ret;
1295146a1439SMasami Hiramatsu 	}
129617f88fcdSMasami Hiramatsu 	if (!strlist__has_entry(namelist, buf))
1297146a1439SMasami Hiramatsu 		return 0;
129817f88fcdSMasami Hiramatsu 
1299d761b08bSMasami Hiramatsu 	if (!allow_suffix) {
1300d761b08bSMasami Hiramatsu 		pr_warning("Error: event \"%s\" already exists. "
1301d761b08bSMasami Hiramatsu 			   "(Use -f to force duplicates.)\n", base);
1302146a1439SMasami Hiramatsu 		return -EEXIST;
1303d761b08bSMasami Hiramatsu 	}
1304d761b08bSMasami Hiramatsu 
130517f88fcdSMasami Hiramatsu 	/* Try to add suffix */
130617f88fcdSMasami Hiramatsu 	for (i = 1; i < MAX_EVENT_INDEX; i++) {
1307b498ce1fSMasami Hiramatsu 		ret = e_snprintf(buf, len, "%s_%d", base, i);
1308146a1439SMasami Hiramatsu 		if (ret < 0) {
1309146a1439SMasami Hiramatsu 			pr_debug("snprintf() failed: %s\n", strerror(-ret));
1310146a1439SMasami Hiramatsu 			return ret;
1311146a1439SMasami Hiramatsu 		}
1312b498ce1fSMasami Hiramatsu 		if (!strlist__has_entry(namelist, buf))
1313b498ce1fSMasami Hiramatsu 			break;
1314b498ce1fSMasami Hiramatsu 	}
1315146a1439SMasami Hiramatsu 	if (i == MAX_EVENT_INDEX) {
1316146a1439SMasami Hiramatsu 		pr_warning("Too many events are on the same function.\n");
1317146a1439SMasami Hiramatsu 		ret = -ERANGE;
1318b498ce1fSMasami Hiramatsu 	}
1319b498ce1fSMasami Hiramatsu 
1320146a1439SMasami Hiramatsu 	return ret;
1321146a1439SMasami Hiramatsu }
1322146a1439SMasami Hiramatsu 
1323146a1439SMasami Hiramatsu static int __add_kprobe_trace_events(struct perf_probe_event *pev,
13244235b045SMasami Hiramatsu 				     struct kprobe_trace_event *tevs,
13254235b045SMasami Hiramatsu 				     int ntevs, bool allow_suffix)
132650656eecSMasami Hiramatsu {
1327146a1439SMasami Hiramatsu 	int i, fd, ret;
132855632770SIngo Molnar 	struct kprobe_trace_event *tev = NULL;
13294235b045SMasami Hiramatsu 	char buf[64];
13304235b045SMasami Hiramatsu 	const char *event, *group;
1331b498ce1fSMasami Hiramatsu 	struct strlist *namelist;
133250656eecSMasami Hiramatsu 
1333f4d7da49SMasami Hiramatsu 	fd = open_kprobe_events(true);
1334146a1439SMasami Hiramatsu 	if (fd < 0)
1335146a1439SMasami Hiramatsu 		return fd;
1336b498ce1fSMasami Hiramatsu 	/* Get current event names */
13374235b045SMasami Hiramatsu 	namelist = get_kprobe_trace_event_names(fd, false);
1338146a1439SMasami Hiramatsu 	if (!namelist) {
1339146a1439SMasami Hiramatsu 		pr_debug("Failed to get current event list.\n");
1340146a1439SMasami Hiramatsu 		return -EIO;
1341146a1439SMasami Hiramatsu 	}
134250656eecSMasami Hiramatsu 
1343146a1439SMasami Hiramatsu 	ret = 0;
13444235b045SMasami Hiramatsu 	printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":");
134502b95dadSMasami Hiramatsu 	for (i = 0; i < ntevs; i++) {
13464235b045SMasami Hiramatsu 		tev = &tevs[i];
13474235b045SMasami Hiramatsu 		if (pev->event)
13484235b045SMasami Hiramatsu 			event = pev->event;
13494235b045SMasami Hiramatsu 		else
13504235b045SMasami Hiramatsu 			if (pev->point.function)
13514235b045SMasami Hiramatsu 				event = pev->point.function;
13524235b045SMasami Hiramatsu 			else
13534235b045SMasami Hiramatsu 				event = tev->point.symbol;
13544235b045SMasami Hiramatsu 		if (pev->group)
13554235b045SMasami Hiramatsu 			group = pev->group;
13564235b045SMasami Hiramatsu 		else
13574235b045SMasami Hiramatsu 			group = PERFPROBE_GROUP;
13584235b045SMasami Hiramatsu 
1359b498ce1fSMasami Hiramatsu 		/* Get an unused new event name */
1360146a1439SMasami Hiramatsu 		ret = get_new_event_name(buf, 64, event,
1361146a1439SMasami Hiramatsu 					 namelist, allow_suffix);
1362146a1439SMasami Hiramatsu 		if (ret < 0)
1363146a1439SMasami Hiramatsu 			break;
13644235b045SMasami Hiramatsu 		event = buf;
13654235b045SMasami Hiramatsu 
136602b95dadSMasami Hiramatsu 		tev->event = strdup(event);
136702b95dadSMasami Hiramatsu 		tev->group = strdup(group);
136802b95dadSMasami Hiramatsu 		if (tev->event == NULL || tev->group == NULL) {
136902b95dadSMasami Hiramatsu 			ret = -ENOMEM;
137002b95dadSMasami Hiramatsu 			break;
137102b95dadSMasami Hiramatsu 		}
1372146a1439SMasami Hiramatsu 		ret = write_kprobe_trace_event(fd, tev);
1373146a1439SMasami Hiramatsu 		if (ret < 0)
1374146a1439SMasami Hiramatsu 			break;
1375b498ce1fSMasami Hiramatsu 		/* Add added event name to namelist */
1376b498ce1fSMasami Hiramatsu 		strlist__add(namelist, event);
13774235b045SMasami Hiramatsu 
13784235b045SMasami Hiramatsu 		/* Trick here - save current event/group */
13794235b045SMasami Hiramatsu 		event = pev->event;
13804235b045SMasami Hiramatsu 		group = pev->group;
13814235b045SMasami Hiramatsu 		pev->event = tev->event;
13824235b045SMasami Hiramatsu 		pev->group = tev->group;
13834235b045SMasami Hiramatsu 		show_perf_probe_event(pev);
13844235b045SMasami Hiramatsu 		/* Trick here - restore current event/group */
13854235b045SMasami Hiramatsu 		pev->event = (char *)event;
13864235b045SMasami Hiramatsu 		pev->group = (char *)group;
13874235b045SMasami Hiramatsu 
1388d761b08bSMasami Hiramatsu 		/*
1389d761b08bSMasami Hiramatsu 		 * Probes after the first probe which comes from same
1390d761b08bSMasami Hiramatsu 		 * user input are always allowed to add suffix, because
1391d761b08bSMasami Hiramatsu 		 * there might be several addresses corresponding to
1392d761b08bSMasami Hiramatsu 		 * one code line.
1393d761b08bSMasami Hiramatsu 		 */
1394d761b08bSMasami Hiramatsu 		allow_suffix = true;
139550656eecSMasami Hiramatsu 	}
1396146a1439SMasami Hiramatsu 
1397146a1439SMasami Hiramatsu 	if (ret >= 0) {
1398a9b495b0SMasami Hiramatsu 		/* Show how to use the event. */
1399a9b495b0SMasami Hiramatsu 		printf("\nYou can now use it on all perf tools, such as:\n\n");
1400146a1439SMasami Hiramatsu 		printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
1401146a1439SMasami Hiramatsu 			 tev->event);
1402146a1439SMasami Hiramatsu 	}
1403a9b495b0SMasami Hiramatsu 
1404e1d2017bSMasami Hiramatsu 	strlist__delete(namelist);
140550656eecSMasami Hiramatsu 	close(fd);
1406146a1439SMasami Hiramatsu 	return ret;
140750656eecSMasami Hiramatsu }
1408fa28244dSMasami Hiramatsu 
14094235b045SMasami Hiramatsu static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
14104235b045SMasami Hiramatsu 					  struct kprobe_trace_event **tevs)
1411e0faa8d3SMasami Hiramatsu {
1412e0faa8d3SMasami Hiramatsu 	struct symbol *sym;
1413e334016fSMasami Hiramatsu 	int ret = 0, i;
14144235b045SMasami Hiramatsu 	struct kprobe_trace_event *tev;
14154235b045SMasami Hiramatsu 
14164b4da7f7SMasami Hiramatsu 	/* Convert perf_probe_event with debuginfo */
1417e334016fSMasami Hiramatsu 	ret = try_to_find_kprobe_trace_events(pev, tevs);
1418e334016fSMasami Hiramatsu 	if (ret != 0)
1419e334016fSMasami Hiramatsu 		return ret;
1420e0faa8d3SMasami Hiramatsu 
14214235b045SMasami Hiramatsu 	/* Allocate trace event buffer */
1422e334016fSMasami Hiramatsu 	tev = *tevs = zalloc(sizeof(struct kprobe_trace_event));
1423e334016fSMasami Hiramatsu 	if (tev == NULL)
1424e334016fSMasami Hiramatsu 		return -ENOMEM;
1425e0faa8d3SMasami Hiramatsu 
14264235b045SMasami Hiramatsu 	/* Copy parameters */
142702b95dadSMasami Hiramatsu 	tev->point.symbol = strdup(pev->point.function);
142802b95dadSMasami Hiramatsu 	if (tev->point.symbol == NULL) {
142902b95dadSMasami Hiramatsu 		ret = -ENOMEM;
143002b95dadSMasami Hiramatsu 		goto error;
143102b95dadSMasami Hiramatsu 	}
14324235b045SMasami Hiramatsu 	tev->point.offset = pev->point.offset;
14334235b045SMasami Hiramatsu 	tev->nargs = pev->nargs;
14344235b045SMasami Hiramatsu 	if (tev->nargs) {
1435e334016fSMasami Hiramatsu 		tev->args = zalloc(sizeof(struct kprobe_trace_arg)
14364235b045SMasami Hiramatsu 				   * tev->nargs);
1437e334016fSMasami Hiramatsu 		if (tev->args == NULL) {
143802b95dadSMasami Hiramatsu 			ret = -ENOMEM;
143902b95dadSMasami Hiramatsu 			goto error;
1440e334016fSMasami Hiramatsu 		}
144148481938SMasami Hiramatsu 		for (i = 0; i < tev->nargs; i++) {
144202b95dadSMasami Hiramatsu 			if (pev->args[i].name) {
144302b95dadSMasami Hiramatsu 				tev->args[i].name = strdup(pev->args[i].name);
144402b95dadSMasami Hiramatsu 				if (tev->args[i].name == NULL) {
144502b95dadSMasami Hiramatsu 					ret = -ENOMEM;
144602b95dadSMasami Hiramatsu 					goto error;
144702b95dadSMasami Hiramatsu 				}
144802b95dadSMasami Hiramatsu 			}
144902b95dadSMasami Hiramatsu 			tev->args[i].value = strdup(pev->args[i].var);
145002b95dadSMasami Hiramatsu 			if (tev->args[i].value == NULL) {
145102b95dadSMasami Hiramatsu 				ret = -ENOMEM;
145202b95dadSMasami Hiramatsu 				goto error;
145302b95dadSMasami Hiramatsu 			}
145402b95dadSMasami Hiramatsu 			if (pev->args[i].type) {
145502b95dadSMasami Hiramatsu 				tev->args[i].type = strdup(pev->args[i].type);
145602b95dadSMasami Hiramatsu 				if (tev->args[i].type == NULL) {
145702b95dadSMasami Hiramatsu 					ret = -ENOMEM;
145802b95dadSMasami Hiramatsu 					goto error;
145902b95dadSMasami Hiramatsu 				}
146002b95dadSMasami Hiramatsu 			}
146148481938SMasami Hiramatsu 		}
1462e0faa8d3SMasami Hiramatsu 	}
1463e0faa8d3SMasami Hiramatsu 
14644235b045SMasami Hiramatsu 	/* Currently just checking function name from symbol map */
14654235b045SMasami Hiramatsu 	sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
14664235b045SMasami Hiramatsu 				       tev->point.symbol, NULL);
1467146a1439SMasami Hiramatsu 	if (!sym) {
1468146a1439SMasami Hiramatsu 		pr_warning("Kernel symbol \'%s\' not found.\n",
14694235b045SMasami Hiramatsu 			   tev->point.symbol);
147002b95dadSMasami Hiramatsu 		ret = -ENOENT;
147102b95dadSMasami Hiramatsu 		goto error;
147202b95dadSMasami Hiramatsu 	}
147302b95dadSMasami Hiramatsu 
147402b95dadSMasami Hiramatsu 	return 1;
147502b95dadSMasami Hiramatsu error:
1476e334016fSMasami Hiramatsu 	clear_kprobe_trace_event(tev);
1477e334016fSMasami Hiramatsu 	free(tev);
1478e334016fSMasami Hiramatsu 	*tevs = NULL;
1479e334016fSMasami Hiramatsu 	return ret;
14804235b045SMasami Hiramatsu }
14814235b045SMasami Hiramatsu 
14824235b045SMasami Hiramatsu struct __event_package {
14834235b045SMasami Hiramatsu 	struct perf_probe_event		*pev;
14844235b045SMasami Hiramatsu 	struct kprobe_trace_event	*tevs;
14854235b045SMasami Hiramatsu 	int				ntevs;
14864235b045SMasami Hiramatsu };
14874235b045SMasami Hiramatsu 
1488146a1439SMasami Hiramatsu int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
14894235b045SMasami Hiramatsu 			  bool force_add)
14904235b045SMasami Hiramatsu {
1491146a1439SMasami Hiramatsu 	int i, j, ret;
14924235b045SMasami Hiramatsu 	struct __event_package *pkgs;
14934235b045SMasami Hiramatsu 
1494e334016fSMasami Hiramatsu 	pkgs = zalloc(sizeof(struct __event_package) * npevs);
1495e334016fSMasami Hiramatsu 	if (pkgs == NULL)
1496e334016fSMasami Hiramatsu 		return -ENOMEM;
14974235b045SMasami Hiramatsu 
14984235b045SMasami Hiramatsu 	/* Init vmlinux path */
1499146a1439SMasami Hiramatsu 	ret = init_vmlinux();
1500146a1439SMasami Hiramatsu 	if (ret < 0)
1501146a1439SMasami Hiramatsu 		return ret;
15024235b045SMasami Hiramatsu 
15034235b045SMasami Hiramatsu 	/* Loop 1: convert all events */
15044235b045SMasami Hiramatsu 	for (i = 0; i < npevs; i++) {
15054235b045SMasami Hiramatsu 		pkgs[i].pev = &pevs[i];
15064235b045SMasami Hiramatsu 		/* Convert with or without debuginfo */
1507146a1439SMasami Hiramatsu 		ret  = convert_to_kprobe_trace_events(pkgs[i].pev,
15084235b045SMasami Hiramatsu 						      &pkgs[i].tevs);
1509146a1439SMasami Hiramatsu 		if (ret < 0)
1510146a1439SMasami Hiramatsu 			goto end;
1511146a1439SMasami Hiramatsu 		pkgs[i].ntevs = ret;
15124235b045SMasami Hiramatsu 	}
15134235b045SMasami Hiramatsu 
15144235b045SMasami Hiramatsu 	/* Loop 2: add all events */
1515146a1439SMasami Hiramatsu 	for (i = 0; i < npevs && ret >= 0; i++)
1516146a1439SMasami Hiramatsu 		ret = __add_kprobe_trace_events(pkgs[i].pev, pkgs[i].tevs,
15174235b045SMasami Hiramatsu 						pkgs[i].ntevs, force_add);
1518146a1439SMasami Hiramatsu end:
1519146a1439SMasami Hiramatsu 	/* Loop 3: cleanup trace events  */
1520146a1439SMasami Hiramatsu 	for (i = 0; i < npevs; i++)
1521146a1439SMasami Hiramatsu 		for (j = 0; j < pkgs[i].ntevs; j++)
1522146a1439SMasami Hiramatsu 			clear_kprobe_trace_event(&pkgs[i].tevs[j]);
1523146a1439SMasami Hiramatsu 
1524146a1439SMasami Hiramatsu 	return ret;
1525e0faa8d3SMasami Hiramatsu }
1526e0faa8d3SMasami Hiramatsu 
1527146a1439SMasami Hiramatsu static int __del_trace_kprobe_event(int fd, struct str_node *ent)
1528bbbb521bSMasami Hiramatsu {
1529bbbb521bSMasami Hiramatsu 	char *p;
1530bbbb521bSMasami Hiramatsu 	char buf[128];
15314235b045SMasami Hiramatsu 	int ret;
1532bbbb521bSMasami Hiramatsu 
1533bbbb521bSMasami Hiramatsu 	/* Convert from perf-probe event to trace-kprobe event */
1534146a1439SMasami Hiramatsu 	ret = e_snprintf(buf, 128, "-:%s", ent->s);
1535146a1439SMasami Hiramatsu 	if (ret < 0)
1536146a1439SMasami Hiramatsu 		goto error;
1537146a1439SMasami Hiramatsu 
1538bbbb521bSMasami Hiramatsu 	p = strchr(buf + 2, ':');
1539146a1439SMasami Hiramatsu 	if (!p) {
1540146a1439SMasami Hiramatsu 		pr_debug("Internal error: %s should have ':' but not.\n",
1541146a1439SMasami Hiramatsu 			 ent->s);
1542146a1439SMasami Hiramatsu 		ret = -ENOTSUP;
1543146a1439SMasami Hiramatsu 		goto error;
1544146a1439SMasami Hiramatsu 	}
1545bbbb521bSMasami Hiramatsu 	*p = '/';
1546bbbb521bSMasami Hiramatsu 
15474235b045SMasami Hiramatsu 	pr_debug("Writing event: %s\n", buf);
15484235b045SMasami Hiramatsu 	ret = write(fd, buf, strlen(buf));
1549146a1439SMasami Hiramatsu 	if (ret < 0)
1550146a1439SMasami Hiramatsu 		goto error;
1551146a1439SMasami Hiramatsu 
1552bbbb521bSMasami Hiramatsu 	printf("Remove event: %s\n", ent->s);
1553146a1439SMasami Hiramatsu 	return 0;
1554146a1439SMasami Hiramatsu error:
1555146a1439SMasami Hiramatsu 	pr_warning("Failed to delete event: %s\n", strerror(-ret));
1556146a1439SMasami Hiramatsu 	return ret;
1557bbbb521bSMasami Hiramatsu }
1558bbbb521bSMasami Hiramatsu 
1559146a1439SMasami Hiramatsu static int del_trace_kprobe_event(int fd, const char *group,
1560fa28244dSMasami Hiramatsu 				  const char *event, struct strlist *namelist)
1561fa28244dSMasami Hiramatsu {
1562fa28244dSMasami Hiramatsu 	char buf[128];
1563bbbb521bSMasami Hiramatsu 	struct str_node *ent, *n;
1564146a1439SMasami Hiramatsu 	int found = 0, ret = 0;
1565fa28244dSMasami Hiramatsu 
1566146a1439SMasami Hiramatsu 	ret = e_snprintf(buf, 128, "%s:%s", group, event);
1567146a1439SMasami Hiramatsu 	if (ret < 0) {
1568146a1439SMasami Hiramatsu 		pr_err("Failed to copy event.");
1569146a1439SMasami Hiramatsu 		return ret;
1570146a1439SMasami Hiramatsu 	}
1571fa28244dSMasami Hiramatsu 
1572bbbb521bSMasami Hiramatsu 	if (strpbrk(buf, "*?")) { /* Glob-exp */
1573bbbb521bSMasami Hiramatsu 		strlist__for_each_safe(ent, n, namelist)
1574bbbb521bSMasami Hiramatsu 			if (strglobmatch(ent->s, buf)) {
1575bbbb521bSMasami Hiramatsu 				found++;
1576146a1439SMasami Hiramatsu 				ret = __del_trace_kprobe_event(fd, ent);
1577146a1439SMasami Hiramatsu 				if (ret < 0)
1578146a1439SMasami Hiramatsu 					break;
15793e340590SMasami Hiramatsu 				strlist__remove(namelist, ent);
1580fa28244dSMasami Hiramatsu 			}
1581bbbb521bSMasami Hiramatsu 	} else {
1582bbbb521bSMasami Hiramatsu 		ent = strlist__find(namelist, buf);
1583bbbb521bSMasami Hiramatsu 		if (ent) {
1584bbbb521bSMasami Hiramatsu 			found++;
1585146a1439SMasami Hiramatsu 			ret = __del_trace_kprobe_event(fd, ent);
1586146a1439SMasami Hiramatsu 			if (ret >= 0)
1587bbbb521bSMasami Hiramatsu 				strlist__remove(namelist, ent);
1588bbbb521bSMasami Hiramatsu 		}
1589bbbb521bSMasami Hiramatsu 	}
1590146a1439SMasami Hiramatsu 	if (found == 0 && ret >= 0)
1591146a1439SMasami Hiramatsu 		pr_info("Info: Event \"%s\" does not exist.\n", buf);
1592146a1439SMasami Hiramatsu 
1593146a1439SMasami Hiramatsu 	return ret;
1594bbbb521bSMasami Hiramatsu }
1595fa28244dSMasami Hiramatsu 
1596146a1439SMasami Hiramatsu int del_perf_probe_events(struct strlist *dellist)
1597fa28244dSMasami Hiramatsu {
1598146a1439SMasami Hiramatsu 	int fd, ret = 0;
1599fa28244dSMasami Hiramatsu 	const char *group, *event;
1600fa28244dSMasami Hiramatsu 	char *p, *str;
1601fa28244dSMasami Hiramatsu 	struct str_node *ent;
1602fa28244dSMasami Hiramatsu 	struct strlist *namelist;
1603fa28244dSMasami Hiramatsu 
1604f4d7da49SMasami Hiramatsu 	fd = open_kprobe_events(true);
1605146a1439SMasami Hiramatsu 	if (fd < 0)
1606146a1439SMasami Hiramatsu 		return fd;
1607146a1439SMasami Hiramatsu 
1608fa28244dSMasami Hiramatsu 	/* Get current event names */
16094235b045SMasami Hiramatsu 	namelist = get_kprobe_trace_event_names(fd, true);
1610146a1439SMasami Hiramatsu 	if (namelist == NULL)
1611146a1439SMasami Hiramatsu 		return -EINVAL;
1612fa28244dSMasami Hiramatsu 
1613adf365f4SMasami Hiramatsu 	strlist__for_each(ent, dellist) {
161402b95dadSMasami Hiramatsu 		str = strdup(ent->s);
161502b95dadSMasami Hiramatsu 		if (str == NULL) {
161602b95dadSMasami Hiramatsu 			ret = -ENOMEM;
161702b95dadSMasami Hiramatsu 			break;
161802b95dadSMasami Hiramatsu 		}
1619bbbb521bSMasami Hiramatsu 		pr_debug("Parsing: %s\n", str);
1620fa28244dSMasami Hiramatsu 		p = strchr(str, ':');
1621fa28244dSMasami Hiramatsu 		if (p) {
1622fa28244dSMasami Hiramatsu 			group = str;
1623fa28244dSMasami Hiramatsu 			*p = '\0';
1624fa28244dSMasami Hiramatsu 			event = p + 1;
1625fa28244dSMasami Hiramatsu 		} else {
1626bbbb521bSMasami Hiramatsu 			group = "*";
1627fa28244dSMasami Hiramatsu 			event = str;
1628fa28244dSMasami Hiramatsu 		}
1629bbbb521bSMasami Hiramatsu 		pr_debug("Group: %s, Event: %s\n", group, event);
1630146a1439SMasami Hiramatsu 		ret = del_trace_kprobe_event(fd, group, event, namelist);
1631fa28244dSMasami Hiramatsu 		free(str);
1632146a1439SMasami Hiramatsu 		if (ret < 0)
1633146a1439SMasami Hiramatsu 			break;
1634fa28244dSMasami Hiramatsu 	}
1635fa28244dSMasami Hiramatsu 	strlist__delete(namelist);
1636fa28244dSMasami Hiramatsu 	close(fd);
1637146a1439SMasami Hiramatsu 
1638146a1439SMasami Hiramatsu 	return ret;
1639fa28244dSMasami Hiramatsu }
1640fa28244dSMasami Hiramatsu 
1641