xref: /linux/tools/perf/util/probe-event.c (revision df0faf4be02996135bc3a06b4f34360449c78084)
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"
454b4da7f7SMasami Hiramatsu #include "trace-event.h"	/* For __unused */
4650656eecSMasami Hiramatsu #include "parse-events.h"	/* For debugfs_path */
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 
5650656eecSMasami Hiramatsu #define semantic_error(msg ...) die("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 */
79e0faa8d3SMasami Hiramatsu static void init_vmlinux(void)
80e0faa8d3SMasami Hiramatsu {
81e0faa8d3SMasami Hiramatsu 	symbol_conf.sort_by_name = true;
82e0faa8d3SMasami Hiramatsu 	if (symbol_conf.vmlinux_name == NULL)
83e0faa8d3SMasami Hiramatsu 		symbol_conf.try_vmlinux_path = true;
84e0faa8d3SMasami Hiramatsu 	else
85e0faa8d3SMasami Hiramatsu 		pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
86e0faa8d3SMasami Hiramatsu 	if (symbol__init() < 0)
87e0faa8d3SMasami Hiramatsu 		die("Failed to init symbol map.");
88e0faa8d3SMasami Hiramatsu 
89e0faa8d3SMasami Hiramatsu 	map_groups__init(&kmap_groups);
90e0faa8d3SMasami Hiramatsu 	if (map_groups__create_kernel_maps(&kmap_groups, kmaps) < 0)
91e0faa8d3SMasami Hiramatsu 		die("Failed to create kernel maps.");
92e0faa8d3SMasami Hiramatsu }
93e0faa8d3SMasami Hiramatsu 
944b4da7f7SMasami Hiramatsu #ifdef DWARF_SUPPORT
95e0faa8d3SMasami Hiramatsu static int open_vmlinux(void)
96e0faa8d3SMasami Hiramatsu {
97e0faa8d3SMasami Hiramatsu 	if (map__load(kmaps[MAP__FUNCTION], NULL) < 0) {
98e0faa8d3SMasami Hiramatsu 		pr_debug("Failed to load kernel map.\n");
99e0faa8d3SMasami Hiramatsu 		return -EINVAL;
100e0faa8d3SMasami Hiramatsu 	}
101e0faa8d3SMasami Hiramatsu 	pr_debug("Try to open %s\n", kmaps[MAP__FUNCTION]->dso->long_name);
102e0faa8d3SMasami Hiramatsu 	return open(kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
103e0faa8d3SMasami Hiramatsu }
1044b4da7f7SMasami Hiramatsu 
1054b4da7f7SMasami Hiramatsu static void convert_to_perf_probe_point(struct kprobe_trace_point *tp,
1064b4da7f7SMasami Hiramatsu 					struct perf_probe_point *pp)
1074b4da7f7SMasami Hiramatsu {
1084b4da7f7SMasami Hiramatsu 	struct symbol *sym;
1094b4da7f7SMasami Hiramatsu 	int fd, ret = 0;
1104b4da7f7SMasami Hiramatsu 
1114b4da7f7SMasami Hiramatsu 	sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
1124b4da7f7SMasami Hiramatsu 				       tp->symbol, NULL);
1134b4da7f7SMasami Hiramatsu 	if (sym) {
1144b4da7f7SMasami Hiramatsu 		fd = open_vmlinux();
1154b4da7f7SMasami Hiramatsu 		ret = find_perf_probe_point(fd, sym->start + tp->offset, pp);
1164b4da7f7SMasami Hiramatsu 		close(fd);
1174b4da7f7SMasami Hiramatsu 	}
1184b4da7f7SMasami Hiramatsu 	if (ret <= 0) {
1194b4da7f7SMasami Hiramatsu 		pp->function = xstrdup(tp->symbol);
1204b4da7f7SMasami Hiramatsu 		pp->offset = tp->offset;
1214b4da7f7SMasami Hiramatsu 	}
1224b4da7f7SMasami Hiramatsu 	pp->retprobe = tp->retprobe;
1234b4da7f7SMasami Hiramatsu }
1244b4da7f7SMasami Hiramatsu 
1254b4da7f7SMasami Hiramatsu /* Try to find perf_probe_event with debuginfo */
1264b4da7f7SMasami Hiramatsu static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
1274b4da7f7SMasami Hiramatsu 					   struct kprobe_trace_event **tevs)
1284b4da7f7SMasami Hiramatsu {
1294b4da7f7SMasami Hiramatsu 	bool need_dwarf = perf_probe_event_need_dwarf(pev);
1304b4da7f7SMasami Hiramatsu 	int fd, ntevs;
1314b4da7f7SMasami Hiramatsu 
1324b4da7f7SMasami Hiramatsu 	fd = open_vmlinux();
1334b4da7f7SMasami Hiramatsu 	if (fd < 0) {
1344b4da7f7SMasami Hiramatsu 		if (need_dwarf)
1354b4da7f7SMasami Hiramatsu 			die("Could not open debuginfo file.");
1364b4da7f7SMasami Hiramatsu 
1374b4da7f7SMasami Hiramatsu 		pr_debug("Could not open vmlinux. Try to use symbols.\n");
1384b4da7f7SMasami Hiramatsu 		return 0;
1394b4da7f7SMasami Hiramatsu 	}
1404b4da7f7SMasami Hiramatsu 
1414b4da7f7SMasami Hiramatsu 	/* Searching trace events corresponding to probe event */
1424b4da7f7SMasami Hiramatsu 	ntevs = find_kprobe_trace_events(fd, pev, tevs);
1434b4da7f7SMasami Hiramatsu 	close(fd);
1444b4da7f7SMasami Hiramatsu 
1454b4da7f7SMasami Hiramatsu 	if (ntevs > 0)	/* Succeeded to find trace events */
1464b4da7f7SMasami Hiramatsu 		return ntevs;
1474b4da7f7SMasami Hiramatsu 
1484b4da7f7SMasami Hiramatsu 	if (ntevs == 0)	/* No error but failed to find probe point. */
1494b4da7f7SMasami Hiramatsu 		die("Probe point '%s' not found. - probe not added.",
1504b4da7f7SMasami Hiramatsu 		    synthesize_perf_probe_point(&pev->point));
1514b4da7f7SMasami Hiramatsu 
1524b4da7f7SMasami Hiramatsu 	/* Error path */
1534b4da7f7SMasami Hiramatsu 	if (need_dwarf) {
1544b4da7f7SMasami Hiramatsu 		if (ntevs == -ENOENT)
1554b4da7f7SMasami Hiramatsu 			pr_warning("No dwarf info found in the vmlinux - "
1564b4da7f7SMasami Hiramatsu 				"please rebuild with CONFIG_DEBUG_INFO=y.\n");
1574b4da7f7SMasami Hiramatsu 		die("Could not analyze debuginfo.");
1584b4da7f7SMasami Hiramatsu 	}
1594b4da7f7SMasami Hiramatsu 	pr_debug("An error occurred in debuginfo analysis."
1604b4da7f7SMasami Hiramatsu 		 " Try to use symbols.\n");
1614b4da7f7SMasami Hiramatsu 	return 0;
1624b4da7f7SMasami Hiramatsu 
1634b4da7f7SMasami Hiramatsu }
1644b4da7f7SMasami Hiramatsu 
1654b4da7f7SMasami Hiramatsu #define LINEBUF_SIZE 256
1664b4da7f7SMasami Hiramatsu #define NR_ADDITIONAL_LINES 2
1674b4da7f7SMasami Hiramatsu 
1684b4da7f7SMasami Hiramatsu static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
1694b4da7f7SMasami Hiramatsu {
1704b4da7f7SMasami Hiramatsu 	char buf[LINEBUF_SIZE];
1714b4da7f7SMasami Hiramatsu 	const char *color = PERF_COLOR_BLUE;
1724b4da7f7SMasami Hiramatsu 
1734b4da7f7SMasami Hiramatsu 	if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
1744b4da7f7SMasami Hiramatsu 		goto error;
1754b4da7f7SMasami Hiramatsu 	if (!skip) {
1764b4da7f7SMasami Hiramatsu 		if (show_num)
1774b4da7f7SMasami Hiramatsu 			fprintf(stdout, "%7u  %s", l, buf);
1784b4da7f7SMasami Hiramatsu 		else
1794b4da7f7SMasami Hiramatsu 			color_fprintf(stdout, color, "         %s", buf);
1804b4da7f7SMasami Hiramatsu 	}
1814b4da7f7SMasami Hiramatsu 
1824b4da7f7SMasami Hiramatsu 	while (strlen(buf) == LINEBUF_SIZE - 1 &&
1834b4da7f7SMasami Hiramatsu 	       buf[LINEBUF_SIZE - 2] != '\n') {
1844b4da7f7SMasami Hiramatsu 		if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
1854b4da7f7SMasami Hiramatsu 			goto error;
1864b4da7f7SMasami Hiramatsu 		if (!skip) {
1874b4da7f7SMasami Hiramatsu 			if (show_num)
1884b4da7f7SMasami Hiramatsu 				fprintf(stdout, "%s", buf);
1894b4da7f7SMasami Hiramatsu 			else
1904b4da7f7SMasami Hiramatsu 				color_fprintf(stdout, color, "%s", buf);
1914b4da7f7SMasami Hiramatsu 		}
1924b4da7f7SMasami Hiramatsu 	}
1934b4da7f7SMasami Hiramatsu 	return;
1944b4da7f7SMasami Hiramatsu error:
1954b4da7f7SMasami Hiramatsu 	if (feof(fp))
1964b4da7f7SMasami Hiramatsu 		die("Source file is shorter than expected.");
1974b4da7f7SMasami Hiramatsu 	else
1984b4da7f7SMasami Hiramatsu 		die("File read error: %s", strerror(errno));
1994b4da7f7SMasami Hiramatsu }
2004b4da7f7SMasami Hiramatsu 
2014b4da7f7SMasami Hiramatsu /*
2024b4da7f7SMasami Hiramatsu  * Show line-range always requires debuginfo to find source file and
2034b4da7f7SMasami Hiramatsu  * line number.
2044b4da7f7SMasami Hiramatsu  */
2054b4da7f7SMasami Hiramatsu void show_line_range(struct line_range *lr)
2064b4da7f7SMasami Hiramatsu {
2074b4da7f7SMasami Hiramatsu 	unsigned int l = 1;
2084b4da7f7SMasami Hiramatsu 	struct line_node *ln;
2094b4da7f7SMasami Hiramatsu 	FILE *fp;
2104b4da7f7SMasami Hiramatsu 	int fd, ret;
2114b4da7f7SMasami Hiramatsu 
2124b4da7f7SMasami Hiramatsu 	/* Search a line range */
2134b4da7f7SMasami Hiramatsu 	init_vmlinux();
2144b4da7f7SMasami Hiramatsu 	fd = open_vmlinux();
2154b4da7f7SMasami Hiramatsu 	if (fd < 0)
2164b4da7f7SMasami Hiramatsu 		die("Could not open debuginfo file.");
2174b4da7f7SMasami Hiramatsu 	ret = find_line_range(fd, lr);
2184b4da7f7SMasami Hiramatsu 	if (ret <= 0)
2194b4da7f7SMasami Hiramatsu 		die("Source line is not found.\n");
2204b4da7f7SMasami Hiramatsu 	close(fd);
2214b4da7f7SMasami Hiramatsu 
2224b4da7f7SMasami Hiramatsu 	setup_pager();
2234b4da7f7SMasami Hiramatsu 
2244b4da7f7SMasami Hiramatsu 	if (lr->function)
2254b4da7f7SMasami Hiramatsu 		fprintf(stdout, "<%s:%d>\n", lr->function,
2264b4da7f7SMasami Hiramatsu 			lr->start - lr->offset);
2274b4da7f7SMasami Hiramatsu 	else
2284b4da7f7SMasami Hiramatsu 		fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
2294b4da7f7SMasami Hiramatsu 
2304b4da7f7SMasami Hiramatsu 	fp = fopen(lr->path, "r");
2314b4da7f7SMasami Hiramatsu 	if (fp == NULL)
2324b4da7f7SMasami Hiramatsu 		die("Failed to open %s: %s", lr->path, strerror(errno));
2334b4da7f7SMasami Hiramatsu 	/* Skip to starting line number */
2344b4da7f7SMasami Hiramatsu 	while (l < lr->start)
2354b4da7f7SMasami Hiramatsu 		show_one_line(fp, l++, true, false);
2364b4da7f7SMasami Hiramatsu 
2374b4da7f7SMasami Hiramatsu 	list_for_each_entry(ln, &lr->line_list, list) {
2384b4da7f7SMasami Hiramatsu 		while (ln->line > l)
2394b4da7f7SMasami Hiramatsu 			show_one_line(fp, (l++) - lr->offset, false, false);
2404b4da7f7SMasami Hiramatsu 		show_one_line(fp, (l++) - lr->offset, false, true);
2414b4da7f7SMasami Hiramatsu 	}
2424b4da7f7SMasami Hiramatsu 
2434b4da7f7SMasami Hiramatsu 	if (lr->end == INT_MAX)
2444b4da7f7SMasami Hiramatsu 		lr->end = l + NR_ADDITIONAL_LINES;
2454b4da7f7SMasami Hiramatsu 	while (l < lr->end && !feof(fp))
2464b4da7f7SMasami Hiramatsu 		show_one_line(fp, (l++) - lr->offset, false, false);
2474b4da7f7SMasami Hiramatsu 
2484b4da7f7SMasami Hiramatsu 	fclose(fp);
2494b4da7f7SMasami Hiramatsu }
2504b4da7f7SMasami Hiramatsu 
2514b4da7f7SMasami Hiramatsu #else	/* !DWARF_SUPPORT */
2524b4da7f7SMasami Hiramatsu 
2534b4da7f7SMasami Hiramatsu static void convert_to_perf_probe_point(struct kprobe_trace_point *tp,
2544b4da7f7SMasami Hiramatsu 					struct perf_probe_point *pp)
2554b4da7f7SMasami Hiramatsu {
2564b4da7f7SMasami Hiramatsu 	pp->function = xstrdup(tp->symbol);
2574b4da7f7SMasami Hiramatsu 	pp->offset = tp->offset;
2584b4da7f7SMasami Hiramatsu 	pp->retprobe = tp->retprobe;
2594b4da7f7SMasami Hiramatsu }
2604b4da7f7SMasami Hiramatsu 
2614b4da7f7SMasami Hiramatsu static int try_to_find_kprobe_trace_events(struct perf_probe_event *pev,
2624b4da7f7SMasami Hiramatsu 				struct kprobe_trace_event **tevs __unused)
2634b4da7f7SMasami Hiramatsu {
2644b4da7f7SMasami Hiramatsu 	if (perf_probe_event_need_dwarf(pev))
2654b4da7f7SMasami Hiramatsu 		die("Debuginfo-analysis is not supported");
2664b4da7f7SMasami Hiramatsu 	return 0;
2674b4da7f7SMasami Hiramatsu }
2684b4da7f7SMasami Hiramatsu 
2694b4da7f7SMasami Hiramatsu void show_line_range(struct line_range *lr __unused)
2704b4da7f7SMasami Hiramatsu {
2714b4da7f7SMasami Hiramatsu 	die("Debuginfo-analysis is not supported");
2724b4da7f7SMasami Hiramatsu }
2734b4da7f7SMasami Hiramatsu 
274e0faa8d3SMasami Hiramatsu #endif
275e0faa8d3SMasami Hiramatsu 
276631c9defSMasami Hiramatsu void parse_line_range_desc(const char *arg, struct line_range *lr)
277631c9defSMasami Hiramatsu {
278631c9defSMasami Hiramatsu 	const char *ptr;
279631c9defSMasami Hiramatsu 	char *tmp;
280631c9defSMasami Hiramatsu 	/*
281631c9defSMasami Hiramatsu 	 * <Syntax>
282631c9defSMasami Hiramatsu 	 * SRC:SLN[+NUM|-ELN]
283631c9defSMasami Hiramatsu 	 * FUNC[:SLN[+NUM|-ELN]]
284631c9defSMasami Hiramatsu 	 */
285631c9defSMasami Hiramatsu 	ptr = strchr(arg, ':');
286631c9defSMasami Hiramatsu 	if (ptr) {
287631c9defSMasami Hiramatsu 		lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0);
288631c9defSMasami Hiramatsu 		if (*tmp == '+')
289631c9defSMasami Hiramatsu 			lr->end = lr->start + (unsigned int)strtoul(tmp + 1,
290631c9defSMasami Hiramatsu 								    &tmp, 0);
291631c9defSMasami Hiramatsu 		else if (*tmp == '-')
292631c9defSMasami Hiramatsu 			lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0);
293631c9defSMasami Hiramatsu 		else
294631c9defSMasami Hiramatsu 			lr->end = 0;
295631c9defSMasami Hiramatsu 		pr_debug("Line range is %u to %u\n", lr->start, lr->end);
296631c9defSMasami Hiramatsu 		if (lr->end && lr->start > lr->end)
297631c9defSMasami Hiramatsu 			semantic_error("Start line must be smaller"
298631c9defSMasami Hiramatsu 				       " than end line.");
299631c9defSMasami Hiramatsu 		if (*tmp != '\0')
300631c9defSMasami Hiramatsu 			semantic_error("Tailing with invalid character '%d'.",
301631c9defSMasami Hiramatsu 				       *tmp);
30231facc5fSMasami Hiramatsu 		tmp = xstrndup(arg, (ptr - arg));
303631c9defSMasami Hiramatsu 	} else
30431facc5fSMasami Hiramatsu 		tmp = xstrdup(arg);
305631c9defSMasami Hiramatsu 
306631c9defSMasami Hiramatsu 	if (strchr(tmp, '.'))
307631c9defSMasami Hiramatsu 		lr->file = tmp;
308631c9defSMasami Hiramatsu 	else
309631c9defSMasami Hiramatsu 		lr->function = tmp;
310631c9defSMasami Hiramatsu }
311631c9defSMasami Hiramatsu 
312b7702a21SMasami Hiramatsu /* Check the name is good for event/group */
313b7702a21SMasami Hiramatsu static bool check_event_name(const char *name)
314b7702a21SMasami Hiramatsu {
315b7702a21SMasami Hiramatsu 	if (!isalpha(*name) && *name != '_')
316b7702a21SMasami Hiramatsu 		return false;
317b7702a21SMasami Hiramatsu 	while (*++name != '\0') {
318b7702a21SMasami Hiramatsu 		if (!isalpha(*name) && !isdigit(*name) && *name != '_')
319b7702a21SMasami Hiramatsu 			return false;
320b7702a21SMasami Hiramatsu 	}
321b7702a21SMasami Hiramatsu 	return true;
322b7702a21SMasami Hiramatsu }
323b7702a21SMasami Hiramatsu 
32450656eecSMasami Hiramatsu /* Parse probepoint definition. */
3254235b045SMasami Hiramatsu static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
32650656eecSMasami Hiramatsu {
3274235b045SMasami Hiramatsu 	struct perf_probe_point *pp = &pev->point;
32850656eecSMasami Hiramatsu 	char *ptr, *tmp;
32950656eecSMasami Hiramatsu 	char c, nc = 0;
33050656eecSMasami Hiramatsu 	/*
33150656eecSMasami Hiramatsu 	 * <Syntax>
3322a9c8c36SMasami Hiramatsu 	 * perf probe [EVENT=]SRC[:LN|;PTN]
3332a9c8c36SMasami Hiramatsu 	 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
334af663d75SMasami Hiramatsu 	 *
335af663d75SMasami Hiramatsu 	 * TODO:Group name support
33650656eecSMasami Hiramatsu 	 */
33750656eecSMasami Hiramatsu 
3382a9c8c36SMasami Hiramatsu 	ptr = strpbrk(arg, ";=@+%");
3392a9c8c36SMasami Hiramatsu 	if (ptr && *ptr == '=') {	/* Event name */
340af663d75SMasami Hiramatsu 		*ptr = '\0';
341af663d75SMasami Hiramatsu 		tmp = ptr + 1;
342af663d75SMasami Hiramatsu 		ptr = strchr(arg, ':');
343af663d75SMasami Hiramatsu 		if (ptr)	/* Group name is not supported yet. */
344af663d75SMasami Hiramatsu 			semantic_error("Group name is not supported yet.");
345b7702a21SMasami Hiramatsu 		if (!check_event_name(arg))
346b7702a21SMasami Hiramatsu 			semantic_error("%s is bad for event name -it must "
347b7702a21SMasami Hiramatsu 				       "follow C symbol-naming rule.", arg);
3484235b045SMasami Hiramatsu 		pev->event = xstrdup(arg);
3494235b045SMasami Hiramatsu 		pev->group = NULL;
350af663d75SMasami Hiramatsu 		arg = tmp;
351af663d75SMasami Hiramatsu 	}
352af663d75SMasami Hiramatsu 
3532a9c8c36SMasami Hiramatsu 	ptr = strpbrk(arg, ";:+@%");
35450656eecSMasami Hiramatsu 	if (ptr) {
35550656eecSMasami Hiramatsu 		nc = *ptr;
35650656eecSMasami Hiramatsu 		*ptr++ = '\0';
35750656eecSMasami Hiramatsu 	}
35850656eecSMasami Hiramatsu 
35950656eecSMasami Hiramatsu 	/* Check arg is function or file and copy it */
36050656eecSMasami Hiramatsu 	if (strchr(arg, '.'))	/* File */
36131facc5fSMasami Hiramatsu 		pp->file = xstrdup(arg);
36250656eecSMasami Hiramatsu 	else			/* Function */
36331facc5fSMasami Hiramatsu 		pp->function = xstrdup(arg);
36450656eecSMasami Hiramatsu 
36550656eecSMasami Hiramatsu 	/* Parse other options */
36650656eecSMasami Hiramatsu 	while (ptr) {
36750656eecSMasami Hiramatsu 		arg = ptr;
36850656eecSMasami Hiramatsu 		c = nc;
3692a9c8c36SMasami Hiramatsu 		if (c == ';') {	/* Lazy pattern must be the last part */
37031facc5fSMasami Hiramatsu 			pp->lazy_line = xstrdup(arg);
3712a9c8c36SMasami Hiramatsu 			break;
3722a9c8c36SMasami Hiramatsu 		}
3732a9c8c36SMasami Hiramatsu 		ptr = strpbrk(arg, ";:+@%");
37450656eecSMasami Hiramatsu 		if (ptr) {
37550656eecSMasami Hiramatsu 			nc = *ptr;
37650656eecSMasami Hiramatsu 			*ptr++ = '\0';
37750656eecSMasami Hiramatsu 		}
37850656eecSMasami Hiramatsu 		switch (c) {
37950656eecSMasami Hiramatsu 		case ':':	/* Line number */
38050656eecSMasami Hiramatsu 			pp->line = strtoul(arg, &tmp, 0);
38150656eecSMasami Hiramatsu 			if (*tmp != '\0')
3822a9c8c36SMasami Hiramatsu 				semantic_error("There is non-digit char"
38350656eecSMasami Hiramatsu 					       " in line number.");
38450656eecSMasami Hiramatsu 			break;
38550656eecSMasami Hiramatsu 		case '+':	/* Byte offset from a symbol */
38650656eecSMasami Hiramatsu 			pp->offset = strtoul(arg, &tmp, 0);
38750656eecSMasami Hiramatsu 			if (*tmp != '\0')
3882a9c8c36SMasami Hiramatsu 				semantic_error("There is non-digit character"
38950656eecSMasami Hiramatsu 						" in offset.");
39050656eecSMasami Hiramatsu 			break;
39150656eecSMasami Hiramatsu 		case '@':	/* File name */
39250656eecSMasami Hiramatsu 			if (pp->file)
39350656eecSMasami Hiramatsu 				semantic_error("SRC@SRC is not allowed.");
39431facc5fSMasami Hiramatsu 			pp->file = xstrdup(arg);
39550656eecSMasami Hiramatsu 			break;
39650656eecSMasami Hiramatsu 		case '%':	/* Probe places */
39750656eecSMasami Hiramatsu 			if (strcmp(arg, "return") == 0) {
39850656eecSMasami Hiramatsu 				pp->retprobe = 1;
39950656eecSMasami Hiramatsu 			} else	/* Others not supported yet */
40050656eecSMasami Hiramatsu 				semantic_error("%%%s is not supported.", arg);
40150656eecSMasami Hiramatsu 			break;
40250656eecSMasami Hiramatsu 		default:
40350656eecSMasami Hiramatsu 			DIE_IF("Program has a bug.");
40450656eecSMasami Hiramatsu 			break;
40550656eecSMasami Hiramatsu 		}
40650656eecSMasami Hiramatsu 	}
40750656eecSMasami Hiramatsu 
40850656eecSMasami Hiramatsu 	/* Exclusion check */
4092a9c8c36SMasami Hiramatsu 	if (pp->lazy_line && pp->line)
4102a9c8c36SMasami Hiramatsu 		semantic_error("Lazy pattern can't be used with line number.");
4112a9c8c36SMasami Hiramatsu 
4122a9c8c36SMasami Hiramatsu 	if (pp->lazy_line && pp->offset)
4132a9c8c36SMasami Hiramatsu 		semantic_error("Lazy pattern can't be used with offset.");
4142a9c8c36SMasami Hiramatsu 
41550656eecSMasami Hiramatsu 	if (pp->line && pp->offset)
41650656eecSMasami Hiramatsu 		semantic_error("Offset can't be used with line number.");
41750656eecSMasami Hiramatsu 
4182a9c8c36SMasami Hiramatsu 	if (!pp->line && !pp->lazy_line && pp->file && !pp->function)
4192a9c8c36SMasami Hiramatsu 		semantic_error("File always requires line number or "
4202a9c8c36SMasami Hiramatsu 			       "lazy pattern.");
42150656eecSMasami Hiramatsu 
42250656eecSMasami Hiramatsu 	if (pp->offset && !pp->function)
42350656eecSMasami Hiramatsu 		semantic_error("Offset requires an entry function.");
42450656eecSMasami Hiramatsu 
42550656eecSMasami Hiramatsu 	if (pp->retprobe && !pp->function)
42650656eecSMasami Hiramatsu 		semantic_error("Return probe requires an entry function.");
42750656eecSMasami Hiramatsu 
4282a9c8c36SMasami Hiramatsu 	if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe)
4292a9c8c36SMasami Hiramatsu 		semantic_error("Offset/Line/Lazy pattern can't be used with "
4302a9c8c36SMasami Hiramatsu 			       "return probe.");
43150656eecSMasami Hiramatsu 
4324235b045SMasami Hiramatsu 	pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
4332a9c8c36SMasami Hiramatsu 		 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
4342a9c8c36SMasami Hiramatsu 		 pp->lazy_line);
43550656eecSMasami Hiramatsu }
43650656eecSMasami Hiramatsu 
4377df2f329SMasami Hiramatsu /* Parse perf-probe event argument */
4387df2f329SMasami Hiramatsu static void parse_perf_probe_arg(const char *str, struct perf_probe_arg *arg)
4397df2f329SMasami Hiramatsu {
44048481938SMasami Hiramatsu 	char *tmp;
4417df2f329SMasami Hiramatsu 	struct perf_probe_arg_field **fieldp;
4427df2f329SMasami Hiramatsu 
4437df2f329SMasami Hiramatsu 	pr_debug("parsing arg: %s into ", str);
4447df2f329SMasami Hiramatsu 
44548481938SMasami Hiramatsu 	tmp = strchr(str, '=');
44648481938SMasami Hiramatsu 	if (tmp) {
44748481938SMasami Hiramatsu 		arg->name = xstrndup(str, tmp - str);
44848481938SMasami Hiramatsu 		str = tmp + 1;
44948481938SMasami Hiramatsu 	}
45048481938SMasami Hiramatsu 
4517df2f329SMasami Hiramatsu 	tmp = strpbrk(str, "-.");
4527df2f329SMasami Hiramatsu 	if (!is_c_varname(str) || !tmp) {
4537df2f329SMasami Hiramatsu 		/* A variable, register, symbol or special value */
45448481938SMasami Hiramatsu 		arg->var = xstrdup(str);
45548481938SMasami Hiramatsu 		pr_debug("%s\n", arg->var);
4567df2f329SMasami Hiramatsu 		return;
4577df2f329SMasami Hiramatsu 	}
4587df2f329SMasami Hiramatsu 
4597df2f329SMasami Hiramatsu 	/* Structure fields */
46048481938SMasami Hiramatsu 	arg->var = xstrndup(str, tmp - str);
46148481938SMasami Hiramatsu 	pr_debug("%s, ", arg->var);
4627df2f329SMasami Hiramatsu 	fieldp = &arg->field;
4637df2f329SMasami Hiramatsu 
4647df2f329SMasami Hiramatsu 	do {
4657df2f329SMasami Hiramatsu 		*fieldp = xzalloc(sizeof(struct perf_probe_arg_field));
4667df2f329SMasami Hiramatsu 		if (*tmp == '.') {
4677df2f329SMasami Hiramatsu 			str = tmp + 1;
4687df2f329SMasami Hiramatsu 			(*fieldp)->ref = false;
4697df2f329SMasami Hiramatsu 		} else if (tmp[1] == '>') {
4707df2f329SMasami Hiramatsu 			str = tmp + 2;
4717df2f329SMasami Hiramatsu 			(*fieldp)->ref = true;
4727df2f329SMasami Hiramatsu 		} else
4737df2f329SMasami Hiramatsu 			semantic_error("Argument parse error: %s", str);
4747df2f329SMasami Hiramatsu 
4757df2f329SMasami Hiramatsu 		tmp = strpbrk(str, "-.");
4767df2f329SMasami Hiramatsu 		if (tmp) {
4777df2f329SMasami Hiramatsu 			(*fieldp)->name = xstrndup(str, tmp - str);
4787df2f329SMasami Hiramatsu 			pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
4797df2f329SMasami Hiramatsu 			fieldp = &(*fieldp)->next;
4807df2f329SMasami Hiramatsu 		}
4817df2f329SMasami Hiramatsu 	} while (tmp);
4827df2f329SMasami Hiramatsu 	(*fieldp)->name = xstrdup(str);
4837df2f329SMasami Hiramatsu 	pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
484*df0faf4bSMasami Hiramatsu 
485*df0faf4bSMasami Hiramatsu 	/* If no name is specified, set the last field name */
486*df0faf4bSMasami Hiramatsu 	if (!arg->name)
487*df0faf4bSMasami Hiramatsu 		arg->name = xstrdup((*fieldp)->name);
4887df2f329SMasami Hiramatsu }
4897df2f329SMasami Hiramatsu 
4904235b045SMasami Hiramatsu /* Parse perf-probe event command */
4914235b045SMasami Hiramatsu void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
49250656eecSMasami Hiramatsu {
493e1c01d61SMasami Hiramatsu 	char **argv;
494fac13fd5SMasami Hiramatsu 	int argc, i;
495fac13fd5SMasami Hiramatsu 
4964235b045SMasami Hiramatsu 	argv = argv_split(cmd, &argc);
497e1c01d61SMasami Hiramatsu 	if (!argv)
498e1c01d61SMasami Hiramatsu 		die("argv_split failed.");
499e1c01d61SMasami Hiramatsu 	if (argc > MAX_PROBE_ARGS + 1)
50050656eecSMasami Hiramatsu 		semantic_error("Too many arguments");
50150656eecSMasami Hiramatsu 
50250656eecSMasami Hiramatsu 	/* Parse probe point */
5034235b045SMasami Hiramatsu 	parse_perf_probe_point(argv[0], pev);
50450656eecSMasami Hiramatsu 
505e1c01d61SMasami Hiramatsu 	/* Copy arguments and ensure return probe has no C argument */
5064235b045SMasami Hiramatsu 	pev->nargs = argc - 1;
5074235b045SMasami Hiramatsu 	pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs);
5084235b045SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++) {
5097df2f329SMasami Hiramatsu 		parse_perf_probe_arg(argv[i + 1], &pev->args[i]);
51048481938SMasami Hiramatsu 		if (is_c_varname(pev->args[i].var) && pev->point.retprobe)
5114235b045SMasami Hiramatsu 			semantic_error("You can't specify local variable for"
5124235b045SMasami Hiramatsu 				       " kretprobe");
513e1c01d61SMasami Hiramatsu 	}
51450656eecSMasami Hiramatsu 
515e1c01d61SMasami Hiramatsu 	argv_free(argv);
51650656eecSMasami Hiramatsu }
51750656eecSMasami Hiramatsu 
5184235b045SMasami Hiramatsu /* Return true if this perf_probe_event requires debuginfo */
5194235b045SMasami Hiramatsu bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
5204de189feSMasami Hiramatsu {
5214235b045SMasami Hiramatsu 	int i;
5224235b045SMasami Hiramatsu 
5234235b045SMasami Hiramatsu 	if (pev->point.file || pev->point.line || pev->point.lazy_line)
5244235b045SMasami Hiramatsu 		return true;
5254235b045SMasami Hiramatsu 
5264235b045SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++)
52748481938SMasami Hiramatsu 		if (is_c_varname(pev->args[i].var))
5284235b045SMasami Hiramatsu 			return true;
5294235b045SMasami Hiramatsu 
5304235b045SMasami Hiramatsu 	return false;
5314235b045SMasami Hiramatsu }
5324235b045SMasami Hiramatsu 
5334235b045SMasami Hiramatsu /* Parse kprobe_events event into struct probe_point */
5344235b045SMasami Hiramatsu void parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev)
5354235b045SMasami Hiramatsu {
5364235b045SMasami Hiramatsu 	struct kprobe_trace_point *tp = &tev->point;
5374de189feSMasami Hiramatsu 	char pr;
5384de189feSMasami Hiramatsu 	char *p;
5394de189feSMasami Hiramatsu 	int ret, i, argc;
5404de189feSMasami Hiramatsu 	char **argv;
5414de189feSMasami Hiramatsu 
5424235b045SMasami Hiramatsu 	pr_debug("Parsing kprobe_events: %s\n", cmd);
5434235b045SMasami Hiramatsu 	argv = argv_split(cmd, &argc);
5444de189feSMasami Hiramatsu 	if (!argv)
5454de189feSMasami Hiramatsu 		die("argv_split failed.");
5464de189feSMasami Hiramatsu 	if (argc < 2)
5474de189feSMasami Hiramatsu 		semantic_error("Too less arguments.");
5484de189feSMasami Hiramatsu 
5494de189feSMasami Hiramatsu 	/* Scan event and group name. */
55093aaa45aSLiming Wang 	ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
5514235b045SMasami Hiramatsu 		     &pr, (float *)(void *)&tev->group,
5524235b045SMasami Hiramatsu 		     (float *)(void *)&tev->event);
5534de189feSMasami Hiramatsu 	if (ret != 3)
5544de189feSMasami Hiramatsu 		semantic_error("Failed to parse event name: %s", argv[0]);
5554235b045SMasami Hiramatsu 	pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr);
5564de189feSMasami Hiramatsu 
5574235b045SMasami Hiramatsu 	tp->retprobe = (pr == 'r');
5584de189feSMasami Hiramatsu 
5594de189feSMasami Hiramatsu 	/* Scan function name and offset */
5604235b045SMasami Hiramatsu 	ret = sscanf(argv[1], "%a[^+]+%lu", (float *)(void *)&tp->symbol,
5614235b045SMasami Hiramatsu 		     &tp->offset);
5624de189feSMasami Hiramatsu 	if (ret == 1)
5634235b045SMasami Hiramatsu 		tp->offset = 0;
5644de189feSMasami Hiramatsu 
5654235b045SMasami Hiramatsu 	tev->nargs = argc - 2;
5664235b045SMasami Hiramatsu 	tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
5674235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
5684de189feSMasami Hiramatsu 		p = strchr(argv[i + 2], '=');
5694de189feSMasami Hiramatsu 		if (p)	/* We don't need which register is assigned. */
5704235b045SMasami Hiramatsu 			*p++ = '\0';
5714235b045SMasami Hiramatsu 		else
5724235b045SMasami Hiramatsu 			p = argv[i + 2];
5734235b045SMasami Hiramatsu 		tev->args[i].name = xstrdup(argv[i + 2]);
5744235b045SMasami Hiramatsu 		/* TODO: parse regs and offset */
5754235b045SMasami Hiramatsu 		tev->args[i].value = xstrdup(p);
5764de189feSMasami Hiramatsu 	}
5774de189feSMasami Hiramatsu 
5784de189feSMasami Hiramatsu 	argv_free(argv);
5794de189feSMasami Hiramatsu }
5804de189feSMasami Hiramatsu 
5817df2f329SMasami Hiramatsu /* Compose only probe arg */
5827df2f329SMasami Hiramatsu int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
5837df2f329SMasami Hiramatsu {
5847df2f329SMasami Hiramatsu 	struct perf_probe_arg_field *field = pa->field;
5857df2f329SMasami Hiramatsu 	int ret;
5867df2f329SMasami Hiramatsu 	char *tmp = buf;
5877df2f329SMasami Hiramatsu 
58848481938SMasami Hiramatsu 	if (pa->name && pa->var)
58948481938SMasami Hiramatsu 		ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var);
59048481938SMasami Hiramatsu 	else
59148481938SMasami Hiramatsu 		ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var);
5927df2f329SMasami Hiramatsu 	if (ret <= 0)
5937df2f329SMasami Hiramatsu 		goto error;
5947df2f329SMasami Hiramatsu 	tmp += ret;
5957df2f329SMasami Hiramatsu 	len -= ret;
5967df2f329SMasami Hiramatsu 
5977df2f329SMasami Hiramatsu 	while (field) {
5987df2f329SMasami Hiramatsu 		ret = e_snprintf(tmp, len, "%s%s", field->ref ? "->" : ".",
5997df2f329SMasami Hiramatsu 				 field->name);
6007df2f329SMasami Hiramatsu 		if (ret <= 0)
6017df2f329SMasami Hiramatsu 			goto error;
6027df2f329SMasami Hiramatsu 		tmp += ret;
6037df2f329SMasami Hiramatsu 		len -= ret;
6047df2f329SMasami Hiramatsu 		field = field->next;
6057df2f329SMasami Hiramatsu 	}
6067df2f329SMasami Hiramatsu 	return tmp - buf;
6077df2f329SMasami Hiramatsu error:
6087df2f329SMasami Hiramatsu 	die("Failed to synthesize perf probe argument: %s", strerror(-ret));
6097df2f329SMasami Hiramatsu }
6107df2f329SMasami Hiramatsu 
6114235b045SMasami Hiramatsu /* Compose only probe point (not argument) */
6124235b045SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
61350656eecSMasami Hiramatsu {
614fb1587d8SMasami Hiramatsu 	char *buf, *tmp;
615fb1587d8SMasami Hiramatsu 	char offs[32] = "", line[32] = "", file[32] = "";
616fb1587d8SMasami Hiramatsu 	int ret, len;
61750656eecSMasami Hiramatsu 
6184235b045SMasami Hiramatsu 	buf = xzalloc(MAX_CMDLEN);
6194de189feSMasami Hiramatsu 	if (pp->offset) {
620fb1587d8SMasami Hiramatsu 		ret = e_snprintf(offs, 32, "+%lu", pp->offset);
6214de189feSMasami Hiramatsu 		if (ret <= 0)
6224de189feSMasami Hiramatsu 			goto error;
6234de189feSMasami Hiramatsu 	}
6244de189feSMasami Hiramatsu 	if (pp->line) {
625fb1587d8SMasami Hiramatsu 		ret = e_snprintf(line, 32, ":%d", pp->line);
626fb1587d8SMasami Hiramatsu 		if (ret <= 0)
627fb1587d8SMasami Hiramatsu 			goto error;
628fb1587d8SMasami Hiramatsu 	}
629fb1587d8SMasami Hiramatsu 	if (pp->file) {
630fb1587d8SMasami Hiramatsu 		len = strlen(pp->file) - 32;
631fb1587d8SMasami Hiramatsu 		if (len < 0)
632fb1587d8SMasami Hiramatsu 			len = 0;
633fb1587d8SMasami Hiramatsu 		tmp = strchr(pp->file + len, '/');
634fb1587d8SMasami Hiramatsu 		if (!tmp)
635fb1587d8SMasami Hiramatsu 			tmp = pp->file + len - 1;
636fb1587d8SMasami Hiramatsu 		ret = e_snprintf(file, 32, "@%s", tmp + 1);
6374de189feSMasami Hiramatsu 		if (ret <= 0)
6384de189feSMasami Hiramatsu 			goto error;
6394de189feSMasami Hiramatsu 	}
6404de189feSMasami Hiramatsu 
6414de189feSMasami Hiramatsu 	if (pp->function)
642fb1587d8SMasami Hiramatsu 		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function,
643fb1587d8SMasami Hiramatsu 				 offs, pp->retprobe ? "%return" : "", line,
644fb1587d8SMasami Hiramatsu 				 file);
6454de189feSMasami Hiramatsu 	else
646fb1587d8SMasami Hiramatsu 		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line);
6474235b045SMasami Hiramatsu 	if (ret <= 0)
6484235b045SMasami Hiramatsu 		goto error;
6494235b045SMasami Hiramatsu 
6504235b045SMasami Hiramatsu 	return buf;
6514235b045SMasami Hiramatsu error:
6524235b045SMasami Hiramatsu 	die("Failed to synthesize perf probe point: %s", strerror(-ret));
6534235b045SMasami Hiramatsu }
6544235b045SMasami Hiramatsu 
6554235b045SMasami Hiramatsu #if 0
6564235b045SMasami Hiramatsu char *synthesize_perf_probe_command(struct perf_probe_event *pev)
6574235b045SMasami Hiramatsu {
6584235b045SMasami Hiramatsu 	char *buf;
6594235b045SMasami Hiramatsu 	int i, len, ret;
6604235b045SMasami Hiramatsu 
6614235b045SMasami Hiramatsu 	buf = synthesize_perf_probe_point(&pev->point);
6624235b045SMasami Hiramatsu 	if (!buf)
6634235b045SMasami Hiramatsu 		return NULL;
6644235b045SMasami Hiramatsu 
6654235b045SMasami Hiramatsu 	len = strlen(buf);
6664235b045SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++) {
6674235b045SMasami Hiramatsu 		ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
6684235b045SMasami Hiramatsu 				 pev->args[i].name);
6697ef17aafSMasami Hiramatsu 		if (ret <= 0) {
6704235b045SMasami Hiramatsu 			free(buf);
6714235b045SMasami Hiramatsu 			return NULL;
6727ef17aafSMasami Hiramatsu 		}
6734235b045SMasami Hiramatsu 		len += ret;
6747ef17aafSMasami Hiramatsu 	}
67550656eecSMasami Hiramatsu 
6764235b045SMasami Hiramatsu 	return buf;
6774235b045SMasami Hiramatsu }
6784235b045SMasami Hiramatsu #endif
6794235b045SMasami Hiramatsu 
6804235b045SMasami Hiramatsu static int __synthesize_kprobe_trace_arg_ref(struct kprobe_trace_arg_ref *ref,
6814235b045SMasami Hiramatsu 					     char **buf, size_t *buflen,
6824235b045SMasami Hiramatsu 					     int depth)
6837ef17aafSMasami Hiramatsu {
6844235b045SMasami Hiramatsu 	int ret;
6854235b045SMasami Hiramatsu 	if (ref->next) {
6864235b045SMasami Hiramatsu 		depth = __synthesize_kprobe_trace_arg_ref(ref->next, buf,
6874235b045SMasami Hiramatsu 							 buflen, depth + 1);
6884235b045SMasami Hiramatsu 		if (depth < 0)
6894235b045SMasami Hiramatsu 			goto out;
6904235b045SMasami Hiramatsu 	}
6914235b045SMasami Hiramatsu 
6924235b045SMasami Hiramatsu 	ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset);
6934235b045SMasami Hiramatsu 	if (ret < 0)
6944235b045SMasami Hiramatsu 		depth = ret;
6954235b045SMasami Hiramatsu 	else {
6964235b045SMasami Hiramatsu 		*buf += ret;
6974235b045SMasami Hiramatsu 		*buflen -= ret;
6984235b045SMasami Hiramatsu 	}
6994235b045SMasami Hiramatsu out:
7004235b045SMasami Hiramatsu 	return depth;
7014235b045SMasami Hiramatsu 
7024235b045SMasami Hiramatsu }
7034235b045SMasami Hiramatsu 
7044235b045SMasami Hiramatsu static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
7054235b045SMasami Hiramatsu 				       char *buf, size_t buflen)
7064235b045SMasami Hiramatsu {
7074235b045SMasami Hiramatsu 	int ret, depth = 0;
7084235b045SMasami Hiramatsu 	char *tmp = buf;
7094235b045SMasami Hiramatsu 
7104235b045SMasami Hiramatsu 	/* Argument name or separator */
7114235b045SMasami Hiramatsu 	if (arg->name)
7124235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, " %s=", arg->name);
7134235b045SMasami Hiramatsu 	else
7144235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, " ");
7154235b045SMasami Hiramatsu 	if (ret < 0)
7164235b045SMasami Hiramatsu 		return ret;
7174235b045SMasami Hiramatsu 	buf += ret;
7184235b045SMasami Hiramatsu 	buflen -= ret;
7194235b045SMasami Hiramatsu 
7204235b045SMasami Hiramatsu 	/* Dereferencing arguments */
7214235b045SMasami Hiramatsu 	if (arg->ref) {
7224235b045SMasami Hiramatsu 		depth = __synthesize_kprobe_trace_arg_ref(arg->ref, &buf,
7234235b045SMasami Hiramatsu 							  &buflen, 1);
7244235b045SMasami Hiramatsu 		if (depth < 0)
7254235b045SMasami Hiramatsu 			return depth;
7264235b045SMasami Hiramatsu 	}
7274235b045SMasami Hiramatsu 
7284235b045SMasami Hiramatsu 	/* Print argument value */
7294235b045SMasami Hiramatsu 	ret = e_snprintf(buf, buflen, "%s", arg->value);
7304235b045SMasami Hiramatsu 	if (ret < 0)
7314235b045SMasami Hiramatsu 		return ret;
7324235b045SMasami Hiramatsu 	buf += ret;
7334235b045SMasami Hiramatsu 	buflen -= ret;
7344235b045SMasami Hiramatsu 
7354235b045SMasami Hiramatsu 	/* Closing */
7364235b045SMasami Hiramatsu 	while (depth--) {
7374235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, ")");
7384235b045SMasami Hiramatsu 		if (ret < 0)
7394235b045SMasami Hiramatsu 			return ret;
7404235b045SMasami Hiramatsu 		buf += ret;
7414235b045SMasami Hiramatsu 		buflen -= ret;
7424235b045SMasami Hiramatsu 	}
7434235b045SMasami Hiramatsu 
7444235b045SMasami Hiramatsu 	return buf - tmp;
7454235b045SMasami Hiramatsu }
7464235b045SMasami Hiramatsu 
7474235b045SMasami Hiramatsu char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev)
7484235b045SMasami Hiramatsu {
7494235b045SMasami Hiramatsu 	struct kprobe_trace_point *tp = &tev->point;
7507ef17aafSMasami Hiramatsu 	char *buf;
7517ef17aafSMasami Hiramatsu 	int i, len, ret;
7527ef17aafSMasami Hiramatsu 
7534235b045SMasami Hiramatsu 	buf = xzalloc(MAX_CMDLEN);
7544235b045SMasami Hiramatsu 	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu",
7554235b045SMasami Hiramatsu 			 tp->retprobe ? 'r' : 'p',
7564235b045SMasami Hiramatsu 			 tev->group, tev->event,
7574235b045SMasami Hiramatsu 			 tp->symbol, tp->offset);
7584235b045SMasami Hiramatsu 	if (len <= 0)
7594235b045SMasami Hiramatsu 		goto error;
7607ef17aafSMasami Hiramatsu 
7614235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
7624235b045SMasami Hiramatsu 		ret = synthesize_kprobe_trace_arg(&tev->args[i], buf + len,
7634235b045SMasami Hiramatsu 						  MAX_CMDLEN - len);
7644de189feSMasami Hiramatsu 		if (ret <= 0)
76550656eecSMasami Hiramatsu 			goto error;
76650656eecSMasami Hiramatsu 		len += ret;
76750656eecSMasami Hiramatsu 	}
76850656eecSMasami Hiramatsu 
7694235b045SMasami Hiramatsu 	return buf;
77050656eecSMasami Hiramatsu error:
7714235b045SMasami Hiramatsu 	free(buf);
7724235b045SMasami Hiramatsu 	return NULL;
77350656eecSMasami Hiramatsu }
77450656eecSMasami Hiramatsu 
7754235b045SMasami Hiramatsu void convert_to_perf_probe_event(struct kprobe_trace_event *tev,
7764235b045SMasami Hiramatsu 				 struct perf_probe_event *pev)
7774de189feSMasami Hiramatsu {
7784235b045SMasami Hiramatsu 	char buf[64];
7794235b045SMasami Hiramatsu 	int i;
7804de189feSMasami Hiramatsu 
7814b4da7f7SMasami Hiramatsu 	/* Convert event/group name */
782fb1587d8SMasami Hiramatsu 	pev->event = xstrdup(tev->event);
783fb1587d8SMasami Hiramatsu 	pev->group = xstrdup(tev->group);
784fb1587d8SMasami Hiramatsu 
7854b4da7f7SMasami Hiramatsu 	/* Convert trace_point to probe_point */
7864b4da7f7SMasami Hiramatsu 	convert_to_perf_probe_point(&tev->point, &pev->point);
7874b4da7f7SMasami Hiramatsu 
7884235b045SMasami Hiramatsu 	/* Convert trace_arg to probe_arg */
7894235b045SMasami Hiramatsu 	pev->nargs = tev->nargs;
7904235b045SMasami Hiramatsu 	pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs);
7914235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++)
7924235b045SMasami Hiramatsu 		if (tev->args[i].name)
7934235b045SMasami Hiramatsu 			pev->args[i].name = xstrdup(tev->args[i].name);
7944235b045SMasami Hiramatsu 		else {
7954235b045SMasami Hiramatsu 			synthesize_kprobe_trace_arg(&tev->args[i], buf, 64);
7964235b045SMasami Hiramatsu 			pev->args[i].name = xstrdup(buf);
7974de189feSMasami Hiramatsu 		}
7984235b045SMasami Hiramatsu }
7994de189feSMasami Hiramatsu 
8004235b045SMasami Hiramatsu void clear_perf_probe_event(struct perf_probe_event *pev)
8014235b045SMasami Hiramatsu {
8024235b045SMasami Hiramatsu 	struct perf_probe_point *pp = &pev->point;
8037df2f329SMasami Hiramatsu 	struct perf_probe_arg_field *field, *next;
8044235b045SMasami Hiramatsu 	int i;
8054de189feSMasami Hiramatsu 
8064235b045SMasami Hiramatsu 	if (pev->event)
8074235b045SMasami Hiramatsu 		free(pev->event);
8084235b045SMasami Hiramatsu 	if (pev->group)
8094235b045SMasami Hiramatsu 		free(pev->group);
8104235b045SMasami Hiramatsu 	if (pp->file)
8114235b045SMasami Hiramatsu 		free(pp->file);
8124235b045SMasami Hiramatsu 	if (pp->function)
8134235b045SMasami Hiramatsu 		free(pp->function);
8144235b045SMasami Hiramatsu 	if (pp->lazy_line)
8154235b045SMasami Hiramatsu 		free(pp->lazy_line);
8167df2f329SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++) {
8174235b045SMasami Hiramatsu 		if (pev->args[i].name)
8184235b045SMasami Hiramatsu 			free(pev->args[i].name);
81948481938SMasami Hiramatsu 		if (pev->args[i].var)
82048481938SMasami Hiramatsu 			free(pev->args[i].var);
8217df2f329SMasami Hiramatsu 		field = pev->args[i].field;
8227df2f329SMasami Hiramatsu 		while (field) {
8237df2f329SMasami Hiramatsu 			next = field->next;
8247df2f329SMasami Hiramatsu 			if (field->name)
8257df2f329SMasami Hiramatsu 				free(field->name);
8267df2f329SMasami Hiramatsu 			free(field);
8277df2f329SMasami Hiramatsu 			field = next;
8287df2f329SMasami Hiramatsu 		}
8297df2f329SMasami Hiramatsu 	}
8304235b045SMasami Hiramatsu 	if (pev->args)
8314235b045SMasami Hiramatsu 		free(pev->args);
8324235b045SMasami Hiramatsu 	memset(pev, 0, sizeof(*pev));
8334235b045SMasami Hiramatsu }
8344235b045SMasami Hiramatsu 
8354235b045SMasami Hiramatsu void clear_kprobe_trace_event(struct kprobe_trace_event *tev)
8364235b045SMasami Hiramatsu {
8374235b045SMasami Hiramatsu 	struct kprobe_trace_arg_ref *ref, *next;
8384235b045SMasami Hiramatsu 	int i;
8394235b045SMasami Hiramatsu 
8404235b045SMasami Hiramatsu 	if (tev->event)
8414235b045SMasami Hiramatsu 		free(tev->event);
8424235b045SMasami Hiramatsu 	if (tev->group)
8434235b045SMasami Hiramatsu 		free(tev->group);
8444235b045SMasami Hiramatsu 	if (tev->point.symbol)
8454235b045SMasami Hiramatsu 		free(tev->point.symbol);
8464235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
8474235b045SMasami Hiramatsu 		if (tev->args[i].name)
8484235b045SMasami Hiramatsu 			free(tev->args[i].name);
8494235b045SMasami Hiramatsu 		if (tev->args[i].value)
8504235b045SMasami Hiramatsu 			free(tev->args[i].value);
8514235b045SMasami Hiramatsu 		ref = tev->args[i].ref;
8524235b045SMasami Hiramatsu 		while (ref) {
8534235b045SMasami Hiramatsu 			next = ref->next;
8544235b045SMasami Hiramatsu 			free(ref);
8554235b045SMasami Hiramatsu 			ref = next;
8564235b045SMasami Hiramatsu 		}
8574235b045SMasami Hiramatsu 	}
8584235b045SMasami Hiramatsu 	if (tev->args)
8594235b045SMasami Hiramatsu 		free(tev->args);
8604235b045SMasami Hiramatsu 	memset(tev, 0, sizeof(*tev));
8614de189feSMasami Hiramatsu }
8624de189feSMasami Hiramatsu 
863f4d7da49SMasami Hiramatsu static int open_kprobe_events(bool readwrite)
8644de189feSMasami Hiramatsu {
8654de189feSMasami Hiramatsu 	char buf[PATH_MAX];
8664de189feSMasami Hiramatsu 	int ret;
8674de189feSMasami Hiramatsu 
8684de189feSMasami Hiramatsu 	ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path);
8694de189feSMasami Hiramatsu 	if (ret < 0)
8704de189feSMasami Hiramatsu 		die("Failed to make kprobe_events path.");
8714de189feSMasami Hiramatsu 
872f4d7da49SMasami Hiramatsu 	if (readwrite && !probe_event_dry_run)
873f4d7da49SMasami Hiramatsu 		ret = open(buf, O_RDWR, O_APPEND);
874f4d7da49SMasami Hiramatsu 	else
875f4d7da49SMasami Hiramatsu 		ret = open(buf, O_RDONLY, 0);
876f4d7da49SMasami Hiramatsu 
8774de189feSMasami Hiramatsu 	if (ret < 0) {
8784de189feSMasami Hiramatsu 		if (errno == ENOENT)
8794de189feSMasami Hiramatsu 			die("kprobe_events file does not exist -"
88063bbd5e2SLiming Wang 			    " please rebuild with CONFIG_KPROBE_EVENT.");
8814de189feSMasami Hiramatsu 		else
8824de189feSMasami Hiramatsu 			die("Could not open kprobe_events file: %s",
8834de189feSMasami Hiramatsu 			    strerror(errno));
8844de189feSMasami Hiramatsu 	}
8854de189feSMasami Hiramatsu 	return ret;
8864de189feSMasami Hiramatsu }
8874de189feSMasami Hiramatsu 
8884de189feSMasami Hiramatsu /* Get raw string list of current kprobe_events */
8894235b045SMasami Hiramatsu static struct strlist *get_kprobe_trace_command_rawlist(int fd)
8904de189feSMasami Hiramatsu {
8914de189feSMasami Hiramatsu 	int ret, idx;
8924de189feSMasami Hiramatsu 	FILE *fp;
8934de189feSMasami Hiramatsu 	char buf[MAX_CMDLEN];
8944de189feSMasami Hiramatsu 	char *p;
8954de189feSMasami Hiramatsu 	struct strlist *sl;
8964de189feSMasami Hiramatsu 
8974de189feSMasami Hiramatsu 	sl = strlist__new(true, NULL);
8984de189feSMasami Hiramatsu 
8994de189feSMasami Hiramatsu 	fp = fdopen(dup(fd), "r");
9004de189feSMasami Hiramatsu 	while (!feof(fp)) {
9014de189feSMasami Hiramatsu 		p = fgets(buf, MAX_CMDLEN, fp);
9024de189feSMasami Hiramatsu 		if (!p)
9034de189feSMasami Hiramatsu 			break;
9044de189feSMasami Hiramatsu 
9054de189feSMasami Hiramatsu 		idx = strlen(p) - 1;
9064de189feSMasami Hiramatsu 		if (p[idx] == '\n')
9074de189feSMasami Hiramatsu 			p[idx] = '\0';
9084de189feSMasami Hiramatsu 		ret = strlist__add(sl, buf);
9094de189feSMasami Hiramatsu 		if (ret < 0)
9104de189feSMasami Hiramatsu 			die("strlist__add failed: %s", strerror(-ret));
9114de189feSMasami Hiramatsu 	}
9124de189feSMasami Hiramatsu 	fclose(fp);
9134de189feSMasami Hiramatsu 
9144de189feSMasami Hiramatsu 	return sl;
9154de189feSMasami Hiramatsu }
9164de189feSMasami Hiramatsu 
917278498d4SMasami Hiramatsu /* Show an event */
9184235b045SMasami Hiramatsu static void show_perf_probe_event(struct perf_probe_event *pev)
919278498d4SMasami Hiramatsu {
9207e990a51SMasami Hiramatsu 	int i, ret;
921278498d4SMasami Hiramatsu 	char buf[128];
9224235b045SMasami Hiramatsu 	char *place;
923278498d4SMasami Hiramatsu 
9244235b045SMasami Hiramatsu 	/* Synthesize only event probe point */
9254235b045SMasami Hiramatsu 	place = synthesize_perf_probe_point(&pev->point);
9264235b045SMasami Hiramatsu 
9274235b045SMasami Hiramatsu 	ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event);
9287e990a51SMasami Hiramatsu 	if (ret < 0)
9297e990a51SMasami Hiramatsu 		die("Failed to copy event: %s", strerror(-ret));
930fb1587d8SMasami Hiramatsu 	printf("  %-20s (on %s", buf, place);
931278498d4SMasami Hiramatsu 
9324235b045SMasami Hiramatsu 	if (pev->nargs > 0) {
933278498d4SMasami Hiramatsu 		printf(" with");
9347df2f329SMasami Hiramatsu 		for (i = 0; i < pev->nargs; i++) {
9357df2f329SMasami Hiramatsu 			synthesize_perf_probe_arg(&pev->args[i], buf, 128);
9367df2f329SMasami Hiramatsu 			printf(" %s", buf);
9377df2f329SMasami Hiramatsu 		}
938278498d4SMasami Hiramatsu 	}
939278498d4SMasami Hiramatsu 	printf(")\n");
9404235b045SMasami Hiramatsu 	free(place);
941278498d4SMasami Hiramatsu }
942278498d4SMasami Hiramatsu 
9434de189feSMasami Hiramatsu /* List up current perf-probe events */
9444de189feSMasami Hiramatsu void show_perf_probe_events(void)
9454de189feSMasami Hiramatsu {
9467ef17aafSMasami Hiramatsu 	int fd;
9474235b045SMasami Hiramatsu 	struct kprobe_trace_event tev;
9484235b045SMasami Hiramatsu 	struct perf_probe_event pev;
9494de189feSMasami Hiramatsu 	struct strlist *rawlist;
9504de189feSMasami Hiramatsu 	struct str_node *ent;
9514de189feSMasami Hiramatsu 
95272041334SMasami Hiramatsu 	setup_pager();
953fb1587d8SMasami Hiramatsu 	init_vmlinux();
9544235b045SMasami Hiramatsu 
9554235b045SMasami Hiramatsu 	memset(&tev, 0, sizeof(tev));
9564235b045SMasami Hiramatsu 	memset(&pev, 0, sizeof(pev));
95772041334SMasami Hiramatsu 
958f4d7da49SMasami Hiramatsu 	fd = open_kprobe_events(false);
9594235b045SMasami Hiramatsu 	rawlist = get_kprobe_trace_command_rawlist(fd);
9604de189feSMasami Hiramatsu 	close(fd);
9614de189feSMasami Hiramatsu 
962adf365f4SMasami Hiramatsu 	strlist__for_each(ent, rawlist) {
9634235b045SMasami Hiramatsu 		parse_kprobe_trace_command(ent->s, &tev);
9644235b045SMasami Hiramatsu 		convert_to_perf_probe_event(&tev, &pev);
965278498d4SMasami Hiramatsu 		/* Show an event */
9664235b045SMasami Hiramatsu 		show_perf_probe_event(&pev);
9674235b045SMasami Hiramatsu 		clear_perf_probe_event(&pev);
9684235b045SMasami Hiramatsu 		clear_kprobe_trace_event(&tev);
9694de189feSMasami Hiramatsu 	}
9704de189feSMasami Hiramatsu 
9714de189feSMasami Hiramatsu 	strlist__delete(rawlist);
9724de189feSMasami Hiramatsu }
9734de189feSMasami Hiramatsu 
974b498ce1fSMasami Hiramatsu /* Get current perf-probe event names */
9754235b045SMasami Hiramatsu static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group)
976b498ce1fSMasami Hiramatsu {
977fa28244dSMasami Hiramatsu 	char buf[128];
978b498ce1fSMasami Hiramatsu 	struct strlist *sl, *rawlist;
979b498ce1fSMasami Hiramatsu 	struct str_node *ent;
9804235b045SMasami Hiramatsu 	struct kprobe_trace_event tev;
981b498ce1fSMasami Hiramatsu 
9824235b045SMasami Hiramatsu 	memset(&tev, 0, sizeof(tev));
983b498ce1fSMasami Hiramatsu 
9844235b045SMasami Hiramatsu 	rawlist = get_kprobe_trace_command_rawlist(fd);
985e1d2017bSMasami Hiramatsu 	sl = strlist__new(true, NULL);
986adf365f4SMasami Hiramatsu 	strlist__for_each(ent, rawlist) {
9874235b045SMasami Hiramatsu 		parse_kprobe_trace_command(ent->s, &tev);
988fa28244dSMasami Hiramatsu 		if (include_group) {
9894235b045SMasami Hiramatsu 			if (e_snprintf(buf, 128, "%s:%s", tev.group,
9904235b045SMasami Hiramatsu 				       tev.event) < 0)
991fa28244dSMasami Hiramatsu 				die("Failed to copy group:event name.");
992fa28244dSMasami Hiramatsu 			strlist__add(sl, buf);
993fa28244dSMasami Hiramatsu 		} else
9944235b045SMasami Hiramatsu 			strlist__add(sl, tev.event);
9954235b045SMasami Hiramatsu 		clear_kprobe_trace_event(&tev);
996b498ce1fSMasami Hiramatsu 	}
997b498ce1fSMasami Hiramatsu 
998b498ce1fSMasami Hiramatsu 	strlist__delete(rawlist);
999b498ce1fSMasami Hiramatsu 
1000b498ce1fSMasami Hiramatsu 	return sl;
1001b498ce1fSMasami Hiramatsu }
1002b498ce1fSMasami Hiramatsu 
10034235b045SMasami Hiramatsu static void write_kprobe_trace_event(int fd, struct kprobe_trace_event *tev)
100450656eecSMasami Hiramatsu {
100550656eecSMasami Hiramatsu 	int ret;
10064235b045SMasami Hiramatsu 	char *buf = synthesize_kprobe_trace_command(tev);
100750656eecSMasami Hiramatsu 
1008fa28244dSMasami Hiramatsu 	pr_debug("Writing event: %s\n", buf);
1009f4d7da49SMasami Hiramatsu 	if (!probe_event_dry_run) {
101050656eecSMasami Hiramatsu 		ret = write(fd, buf, strlen(buf));
101150656eecSMasami Hiramatsu 		if (ret <= 0)
1012fa28244dSMasami Hiramatsu 			die("Failed to write event: %s", strerror(errno));
101350656eecSMasami Hiramatsu 	}
10144235b045SMasami Hiramatsu 	free(buf);
1015f4d7da49SMasami Hiramatsu }
101650656eecSMasami Hiramatsu 
1017b498ce1fSMasami Hiramatsu static void get_new_event_name(char *buf, size_t len, const char *base,
1018d761b08bSMasami Hiramatsu 			       struct strlist *namelist, bool allow_suffix)
1019b498ce1fSMasami Hiramatsu {
1020b498ce1fSMasami Hiramatsu 	int i, ret;
102117f88fcdSMasami Hiramatsu 
102217f88fcdSMasami Hiramatsu 	/* Try no suffix */
102317f88fcdSMasami Hiramatsu 	ret = e_snprintf(buf, len, "%s", base);
102417f88fcdSMasami Hiramatsu 	if (ret < 0)
102517f88fcdSMasami Hiramatsu 		die("snprintf() failed: %s", strerror(-ret));
102617f88fcdSMasami Hiramatsu 	if (!strlist__has_entry(namelist, buf))
102717f88fcdSMasami Hiramatsu 		return;
102817f88fcdSMasami Hiramatsu 
1029d761b08bSMasami Hiramatsu 	if (!allow_suffix) {
1030d761b08bSMasami Hiramatsu 		pr_warning("Error: event \"%s\" already exists. "
1031d761b08bSMasami Hiramatsu 			   "(Use -f to force duplicates.)\n", base);
1032d761b08bSMasami Hiramatsu 		die("Can't add new event.");
1033d761b08bSMasami Hiramatsu 	}
1034d761b08bSMasami Hiramatsu 
103517f88fcdSMasami Hiramatsu 	/* Try to add suffix */
103617f88fcdSMasami Hiramatsu 	for (i = 1; i < MAX_EVENT_INDEX; i++) {
1037b498ce1fSMasami Hiramatsu 		ret = e_snprintf(buf, len, "%s_%d", base, i);
1038b498ce1fSMasami Hiramatsu 		if (ret < 0)
1039b498ce1fSMasami Hiramatsu 			die("snprintf() failed: %s", strerror(-ret));
1040b498ce1fSMasami Hiramatsu 		if (!strlist__has_entry(namelist, buf))
1041b498ce1fSMasami Hiramatsu 			break;
1042b498ce1fSMasami Hiramatsu 	}
1043b498ce1fSMasami Hiramatsu 	if (i == MAX_EVENT_INDEX)
1044b498ce1fSMasami Hiramatsu 		die("Too many events are on the same function.");
1045b498ce1fSMasami Hiramatsu }
1046b498ce1fSMasami Hiramatsu 
10474235b045SMasami Hiramatsu static void __add_kprobe_trace_events(struct perf_probe_event *pev,
10484235b045SMasami Hiramatsu 				      struct kprobe_trace_event *tevs,
10494235b045SMasami Hiramatsu 				      int ntevs, bool allow_suffix)
105050656eecSMasami Hiramatsu {
10514235b045SMasami Hiramatsu 	int i, fd;
105255632770SIngo Molnar 	struct kprobe_trace_event *tev = NULL;
10534235b045SMasami Hiramatsu 	char buf[64];
10544235b045SMasami Hiramatsu 	const char *event, *group;
1055b498ce1fSMasami Hiramatsu 	struct strlist *namelist;
105650656eecSMasami Hiramatsu 
1057f4d7da49SMasami Hiramatsu 	fd = open_kprobe_events(true);
1058b498ce1fSMasami Hiramatsu 	/* Get current event names */
10594235b045SMasami Hiramatsu 	namelist = get_kprobe_trace_event_names(fd, false);
106050656eecSMasami Hiramatsu 
10614235b045SMasami Hiramatsu 	printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":");
10624235b045SMasami Hiramatsu 	for (i = 0; i < ntevs; i++) {
10634235b045SMasami Hiramatsu 		tev = &tevs[i];
10644235b045SMasami Hiramatsu 		if (pev->event)
10654235b045SMasami Hiramatsu 			event = pev->event;
10664235b045SMasami Hiramatsu 		else
10674235b045SMasami Hiramatsu 			if (pev->point.function)
10684235b045SMasami Hiramatsu 				event = pev->point.function;
10694235b045SMasami Hiramatsu 			else
10704235b045SMasami Hiramatsu 				event = tev->point.symbol;
10714235b045SMasami Hiramatsu 		if (pev->group)
10724235b045SMasami Hiramatsu 			group = pev->group;
10734235b045SMasami Hiramatsu 		else
10744235b045SMasami Hiramatsu 			group = PERFPROBE_GROUP;
10754235b045SMasami Hiramatsu 
1076b498ce1fSMasami Hiramatsu 		/* Get an unused new event name */
10774235b045SMasami Hiramatsu 		get_new_event_name(buf, 64, event, namelist, allow_suffix);
10784235b045SMasami Hiramatsu 		event = buf;
10794235b045SMasami Hiramatsu 
10804235b045SMasami Hiramatsu 		tev->event = xstrdup(event);
10814235b045SMasami Hiramatsu 		tev->group = xstrdup(group);
10824235b045SMasami Hiramatsu 		write_kprobe_trace_event(fd, tev);
1083b498ce1fSMasami Hiramatsu 		/* Add added event name to namelist */
1084b498ce1fSMasami Hiramatsu 		strlist__add(namelist, event);
10854235b045SMasami Hiramatsu 
10864235b045SMasami Hiramatsu 		/* Trick here - save current event/group */
10874235b045SMasami Hiramatsu 		event = pev->event;
10884235b045SMasami Hiramatsu 		group = pev->group;
10894235b045SMasami Hiramatsu 		pev->event = tev->event;
10904235b045SMasami Hiramatsu 		pev->group = tev->group;
10914235b045SMasami Hiramatsu 		show_perf_probe_event(pev);
10924235b045SMasami Hiramatsu 		/* Trick here - restore current event/group */
10934235b045SMasami Hiramatsu 		pev->event = (char *)event;
10944235b045SMasami Hiramatsu 		pev->group = (char *)group;
10954235b045SMasami Hiramatsu 
1096d761b08bSMasami Hiramatsu 		/*
1097d761b08bSMasami Hiramatsu 		 * Probes after the first probe which comes from same
1098d761b08bSMasami Hiramatsu 		 * user input are always allowed to add suffix, because
1099d761b08bSMasami Hiramatsu 		 * there might be several addresses corresponding to
1100d761b08bSMasami Hiramatsu 		 * one code line.
1101d761b08bSMasami Hiramatsu 		 */
1102d761b08bSMasami Hiramatsu 		allow_suffix = true;
110350656eecSMasami Hiramatsu 	}
1104a9b495b0SMasami Hiramatsu 	/* Show how to use the event. */
1105a9b495b0SMasami Hiramatsu 	printf("\nYou can now use it on all perf tools, such as:\n\n");
11064235b045SMasami Hiramatsu 	printf("\tperf record -e %s:%s -a sleep 1\n\n", tev->group, tev->event);
1107a9b495b0SMasami Hiramatsu 
1108e1d2017bSMasami Hiramatsu 	strlist__delete(namelist);
110950656eecSMasami Hiramatsu 	close(fd);
111050656eecSMasami Hiramatsu }
1111fa28244dSMasami Hiramatsu 
11124235b045SMasami Hiramatsu static int convert_to_kprobe_trace_events(struct perf_probe_event *pev,
11134235b045SMasami Hiramatsu 					  struct kprobe_trace_event **tevs)
1114e0faa8d3SMasami Hiramatsu {
1115e0faa8d3SMasami Hiramatsu 	struct symbol *sym;
11164235b045SMasami Hiramatsu 	int ntevs = 0, i;
11174235b045SMasami Hiramatsu 	struct kprobe_trace_event *tev;
11184235b045SMasami Hiramatsu 
11194b4da7f7SMasami Hiramatsu 	/* Convert perf_probe_event with debuginfo */
11204b4da7f7SMasami Hiramatsu 	ntevs = try_to_find_kprobe_trace_events(pev, tevs);
11214b4da7f7SMasami Hiramatsu 	if (ntevs > 0)
11224b4da7f7SMasami Hiramatsu 		return ntevs;
1123e0faa8d3SMasami Hiramatsu 
11244235b045SMasami Hiramatsu 	/* Allocate trace event buffer */
11254235b045SMasami Hiramatsu 	ntevs = 1;
11264235b045SMasami Hiramatsu 	tev = *tevs = xzalloc(sizeof(struct kprobe_trace_event));
1127e0faa8d3SMasami Hiramatsu 
11284235b045SMasami Hiramatsu 	/* Copy parameters */
11294235b045SMasami Hiramatsu 	tev->point.symbol = xstrdup(pev->point.function);
11304235b045SMasami Hiramatsu 	tev->point.offset = pev->point.offset;
11314235b045SMasami Hiramatsu 	tev->nargs = pev->nargs;
11324235b045SMasami Hiramatsu 	if (tev->nargs) {
11334235b045SMasami Hiramatsu 		tev->args = xzalloc(sizeof(struct kprobe_trace_arg)
11344235b045SMasami Hiramatsu 				    * tev->nargs);
113548481938SMasami Hiramatsu 		for (i = 0; i < tev->nargs; i++) {
113648481938SMasami Hiramatsu 			if (pev->args[i].name)
113748481938SMasami Hiramatsu 				tev->args[i].name = xstrdup(pev->args[i].name);
113848481938SMasami Hiramatsu 			tev->args[i].value = xstrdup(pev->args[i].var);
113948481938SMasami Hiramatsu 		}
1140e0faa8d3SMasami Hiramatsu 	}
1141e0faa8d3SMasami Hiramatsu 
11424235b045SMasami Hiramatsu 	/* Currently just checking function name from symbol map */
11434235b045SMasami Hiramatsu 	sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION],
11444235b045SMasami Hiramatsu 				       tev->point.symbol, NULL);
11454235b045SMasami Hiramatsu 	if (!sym)
11464235b045SMasami Hiramatsu 		die("Kernel symbol \'%s\' not found - probe not added.",
11474235b045SMasami Hiramatsu 		    tev->point.symbol);
11484b4da7f7SMasami Hiramatsu 
11494235b045SMasami Hiramatsu 	return ntevs;
11504235b045SMasami Hiramatsu }
11514235b045SMasami Hiramatsu 
11524235b045SMasami Hiramatsu struct __event_package {
11534235b045SMasami Hiramatsu 	struct perf_probe_event		*pev;
11544235b045SMasami Hiramatsu 	struct kprobe_trace_event	*tevs;
11554235b045SMasami Hiramatsu 	int				ntevs;
11564235b045SMasami Hiramatsu };
11574235b045SMasami Hiramatsu 
11584235b045SMasami Hiramatsu void add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
11594235b045SMasami Hiramatsu 			   bool force_add)
11604235b045SMasami Hiramatsu {
11614235b045SMasami Hiramatsu 	int i;
11624235b045SMasami Hiramatsu 	struct __event_package *pkgs;
11634235b045SMasami Hiramatsu 
11644235b045SMasami Hiramatsu 	pkgs = xzalloc(sizeof(struct __event_package) * npevs);
11654235b045SMasami Hiramatsu 
11664235b045SMasami Hiramatsu 	/* Init vmlinux path */
11674235b045SMasami Hiramatsu 	init_vmlinux();
11684235b045SMasami Hiramatsu 
11694235b045SMasami Hiramatsu 	/* Loop 1: convert all events */
11704235b045SMasami Hiramatsu 	for (i = 0; i < npevs; i++) {
11714235b045SMasami Hiramatsu 		pkgs[i].pev = &pevs[i];
11724235b045SMasami Hiramatsu 		/* Convert with or without debuginfo */
11734235b045SMasami Hiramatsu 		pkgs[i].ntevs = convert_to_kprobe_trace_events(pkgs[i].pev,
11744235b045SMasami Hiramatsu 							       &pkgs[i].tevs);
11754235b045SMasami Hiramatsu 	}
11764235b045SMasami Hiramatsu 
11774235b045SMasami Hiramatsu 	/* Loop 2: add all events */
11784235b045SMasami Hiramatsu 	for (i = 0; i < npevs; i++)
11794235b045SMasami Hiramatsu 		__add_kprobe_trace_events(pkgs[i].pev, pkgs[i].tevs,
11804235b045SMasami Hiramatsu 					  pkgs[i].ntevs, force_add);
11814235b045SMasami Hiramatsu 	/* TODO: cleanup all trace events? */
1182e0faa8d3SMasami Hiramatsu }
1183e0faa8d3SMasami Hiramatsu 
1184bbbb521bSMasami Hiramatsu static void __del_trace_kprobe_event(int fd, struct str_node *ent)
1185bbbb521bSMasami Hiramatsu {
1186bbbb521bSMasami Hiramatsu 	char *p;
1187bbbb521bSMasami Hiramatsu 	char buf[128];
11884235b045SMasami Hiramatsu 	int ret;
1189bbbb521bSMasami Hiramatsu 
1190bbbb521bSMasami Hiramatsu 	/* Convert from perf-probe event to trace-kprobe event */
1191bbbb521bSMasami Hiramatsu 	if (e_snprintf(buf, 128, "-:%s", ent->s) < 0)
1192bbbb521bSMasami Hiramatsu 		die("Failed to copy event.");
1193bbbb521bSMasami Hiramatsu 	p = strchr(buf + 2, ':');
1194bbbb521bSMasami Hiramatsu 	if (!p)
1195bbbb521bSMasami Hiramatsu 		die("Internal error: %s should have ':' but not.", ent->s);
1196bbbb521bSMasami Hiramatsu 	*p = '/';
1197bbbb521bSMasami Hiramatsu 
11984235b045SMasami Hiramatsu 	pr_debug("Writing event: %s\n", buf);
11994235b045SMasami Hiramatsu 	ret = write(fd, buf, strlen(buf));
12004235b045SMasami Hiramatsu 	if (ret <= 0)
12014235b045SMasami Hiramatsu 		die("Failed to write event: %s", strerror(errno));
1202bbbb521bSMasami Hiramatsu 	printf("Remove event: %s\n", ent->s);
1203bbbb521bSMasami Hiramatsu }
1204bbbb521bSMasami Hiramatsu 
1205fa28244dSMasami Hiramatsu static void del_trace_kprobe_event(int fd, const char *group,
1206fa28244dSMasami Hiramatsu 				   const char *event, struct strlist *namelist)
1207fa28244dSMasami Hiramatsu {
1208fa28244dSMasami Hiramatsu 	char buf[128];
1209bbbb521bSMasami Hiramatsu 	struct str_node *ent, *n;
1210bbbb521bSMasami Hiramatsu 	int found = 0;
1211fa28244dSMasami Hiramatsu 
1212fa28244dSMasami Hiramatsu 	if (e_snprintf(buf, 128, "%s:%s", group, event) < 0)
1213fa28244dSMasami Hiramatsu 		die("Failed to copy event.");
1214fa28244dSMasami Hiramatsu 
1215bbbb521bSMasami Hiramatsu 	if (strpbrk(buf, "*?")) { /* Glob-exp */
1216bbbb521bSMasami Hiramatsu 		strlist__for_each_safe(ent, n, namelist)
1217bbbb521bSMasami Hiramatsu 			if (strglobmatch(ent->s, buf)) {
1218bbbb521bSMasami Hiramatsu 				found++;
1219bbbb521bSMasami Hiramatsu 				__del_trace_kprobe_event(fd, ent);
12203e340590SMasami Hiramatsu 				strlist__remove(namelist, ent);
1221fa28244dSMasami Hiramatsu 			}
1222bbbb521bSMasami Hiramatsu 	} else {
1223bbbb521bSMasami Hiramatsu 		ent = strlist__find(namelist, buf);
1224bbbb521bSMasami Hiramatsu 		if (ent) {
1225bbbb521bSMasami Hiramatsu 			found++;
1226bbbb521bSMasami Hiramatsu 			__del_trace_kprobe_event(fd, ent);
1227bbbb521bSMasami Hiramatsu 			strlist__remove(namelist, ent);
1228bbbb521bSMasami Hiramatsu 		}
1229bbbb521bSMasami Hiramatsu 	}
1230bbbb521bSMasami Hiramatsu 	if (found == 0)
1231bbbb521bSMasami Hiramatsu 		pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf);
1232bbbb521bSMasami Hiramatsu }
1233fa28244dSMasami Hiramatsu 
12344235b045SMasami Hiramatsu void del_perf_probe_events(struct strlist *dellist)
1235fa28244dSMasami Hiramatsu {
1236fa28244dSMasami Hiramatsu 	int fd;
1237fa28244dSMasami Hiramatsu 	const char *group, *event;
1238fa28244dSMasami Hiramatsu 	char *p, *str;
1239fa28244dSMasami Hiramatsu 	struct str_node *ent;
1240fa28244dSMasami Hiramatsu 	struct strlist *namelist;
1241fa28244dSMasami Hiramatsu 
1242f4d7da49SMasami Hiramatsu 	fd = open_kprobe_events(true);
1243fa28244dSMasami Hiramatsu 	/* Get current event names */
12444235b045SMasami Hiramatsu 	namelist = get_kprobe_trace_event_names(fd, true);
1245fa28244dSMasami Hiramatsu 
1246adf365f4SMasami Hiramatsu 	strlist__for_each(ent, dellist) {
124731facc5fSMasami Hiramatsu 		str = xstrdup(ent->s);
1248bbbb521bSMasami Hiramatsu 		pr_debug("Parsing: %s\n", str);
1249fa28244dSMasami Hiramatsu 		p = strchr(str, ':');
1250fa28244dSMasami Hiramatsu 		if (p) {
1251fa28244dSMasami Hiramatsu 			group = str;
1252fa28244dSMasami Hiramatsu 			*p = '\0';
1253fa28244dSMasami Hiramatsu 			event = p + 1;
1254fa28244dSMasami Hiramatsu 		} else {
1255bbbb521bSMasami Hiramatsu 			group = "*";
1256fa28244dSMasami Hiramatsu 			event = str;
1257fa28244dSMasami Hiramatsu 		}
1258bbbb521bSMasami Hiramatsu 		pr_debug("Group: %s, Event: %s\n", group, event);
1259fa28244dSMasami Hiramatsu 		del_trace_kprobe_event(fd, group, event, namelist);
1260fa28244dSMasami Hiramatsu 		free(str);
1261fa28244dSMasami Hiramatsu 	}
1262fa28244dSMasami Hiramatsu 	strlist__delete(namelist);
1263fa28244dSMasami Hiramatsu 	close(fd);
1264fa28244dSMasami Hiramatsu }
1265fa28244dSMasami Hiramatsu 
1266