xref: /linux/tools/perf/util/probe-event.c (revision 62c15fc49bd1b35d79b34ea96f132ab435e2215a)
150656eecSMasami Hiramatsu /*
20e60836bSSrikar Dronamraju  * probe-event.c : perf-probe definition to probe_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);
75d28c6223SArnaldo Carvalho de Melo static struct machine machine;
76e0faa8d3SMasami Hiramatsu 
77469b9b88SMasami Hiramatsu /* Initialize symbol maps and path of vmlinux/modules */
78146a1439SMasami Hiramatsu static int init_vmlinux(void)
79e0faa8d3SMasami Hiramatsu {
80146a1439SMasami Hiramatsu 	int ret;
81146a1439SMasami Hiramatsu 
82e0faa8d3SMasami Hiramatsu 	symbol_conf.sort_by_name = true;
83e0faa8d3SMasami Hiramatsu 	if (symbol_conf.vmlinux_name == NULL)
84e0faa8d3SMasami Hiramatsu 		symbol_conf.try_vmlinux_path = true;
85e0faa8d3SMasami Hiramatsu 	else
86e0faa8d3SMasami Hiramatsu 		pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
87146a1439SMasami Hiramatsu 	ret = symbol__init();
88146a1439SMasami Hiramatsu 	if (ret < 0) {
89146a1439SMasami Hiramatsu 		pr_debug("Failed to init symbol map.\n");
90146a1439SMasami Hiramatsu 		goto out;
91146a1439SMasami Hiramatsu 	}
92e0faa8d3SMasami Hiramatsu 
93469b9b88SMasami Hiramatsu 	ret = machine__init(&machine, "", HOST_KERNEL_ID);
94d28c6223SArnaldo Carvalho de Melo 	if (ret < 0)
95d28c6223SArnaldo Carvalho de Melo 		goto out;
96d28c6223SArnaldo Carvalho de Melo 
97469b9b88SMasami Hiramatsu 	if (machine__create_kernel_maps(&machine) < 0) {
980e43e5d2SMasami Hiramatsu 		pr_debug("machine__create_kernel_maps() failed.\n");
99469b9b88SMasami Hiramatsu 		goto out;
100469b9b88SMasami Hiramatsu 	}
101146a1439SMasami Hiramatsu out:
102146a1439SMasami Hiramatsu 	if (ret < 0)
103146a1439SMasami Hiramatsu 		pr_warning("Failed to init vmlinux path.\n");
104146a1439SMasami Hiramatsu 	return ret;
105e0faa8d3SMasami Hiramatsu }
106e0faa8d3SMasami Hiramatsu 
107469b9b88SMasami Hiramatsu static struct symbol *__find_kernel_function_by_name(const char *name,
108469b9b88SMasami Hiramatsu 						     struct map **mapp)
109e0faa8d3SMasami Hiramatsu {
110469b9b88SMasami Hiramatsu 	return machine__find_kernel_function_by_name(&machine, name, mapp,
111469b9b88SMasami Hiramatsu 						     NULL);
112e0faa8d3SMasami Hiramatsu }
113469b9b88SMasami Hiramatsu 
114469b9b88SMasami Hiramatsu const char *kernel_get_module_path(const char *module)
115469b9b88SMasami Hiramatsu {
116469b9b88SMasami Hiramatsu 	struct dso *dso;
117469b9b88SMasami Hiramatsu 
118469b9b88SMasami Hiramatsu 	if (module) {
119469b9b88SMasami Hiramatsu 		list_for_each_entry(dso, &machine.kernel_dsos, node) {
120469b9b88SMasami Hiramatsu 			if (strncmp(dso->short_name + 1, module,
121469b9b88SMasami Hiramatsu 				    dso->short_name_len - 2) == 0)
122469b9b88SMasami Hiramatsu 				goto found;
123469b9b88SMasami Hiramatsu 		}
124469b9b88SMasami Hiramatsu 		pr_debug("Failed to find module %s.\n", module);
125469b9b88SMasami Hiramatsu 		return NULL;
126469b9b88SMasami Hiramatsu 	} else {
127469b9b88SMasami Hiramatsu 		dso = machine.vmlinux_maps[MAP__FUNCTION]->dso;
128469b9b88SMasami Hiramatsu 		if (dso__load_vmlinux_path(dso,
129469b9b88SMasami Hiramatsu 			 machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
130469b9b88SMasami Hiramatsu 			pr_debug("Failed to load kernel map.\n");
131469b9b88SMasami Hiramatsu 			return NULL;
132469b9b88SMasami Hiramatsu 		}
133469b9b88SMasami Hiramatsu 	}
134469b9b88SMasami Hiramatsu found:
135469b9b88SMasami Hiramatsu 	return dso->long_name;
136469b9b88SMasami Hiramatsu }
137469b9b88SMasami Hiramatsu 
138469b9b88SMasami Hiramatsu #ifdef DWARF_SUPPORT
139469b9b88SMasami Hiramatsu static int open_vmlinux(const char *module)
140469b9b88SMasami Hiramatsu {
141469b9b88SMasami Hiramatsu 	const char *path = kernel_get_module_path(module);
142469b9b88SMasami Hiramatsu 	if (!path) {
1430e43e5d2SMasami Hiramatsu 		pr_err("Failed to find path of %s module.\n",
1440e43e5d2SMasami Hiramatsu 		       module ?: "kernel");
145469b9b88SMasami Hiramatsu 		return -ENOENT;
146469b9b88SMasami Hiramatsu 	}
147469b9b88SMasami Hiramatsu 	pr_debug("Try to open %s\n", path);
148469b9b88SMasami Hiramatsu 	return open(path, O_RDONLY);
149e0faa8d3SMasami Hiramatsu }
1504b4da7f7SMasami Hiramatsu 
1510e60836bSSrikar Dronamraju /*
1520e60836bSSrikar Dronamraju  * Convert trace point to probe point with debuginfo
1530e60836bSSrikar Dronamraju  * Currently only handles kprobes.
1540e60836bSSrikar Dronamraju  */
1550e60836bSSrikar Dronamraju static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
1564b4da7f7SMasami Hiramatsu 					struct perf_probe_point *pp)
1574b4da7f7SMasami Hiramatsu {
1584b4da7f7SMasami Hiramatsu 	struct symbol *sym;
159469b9b88SMasami Hiramatsu 	struct map *map;
160469b9b88SMasami Hiramatsu 	u64 addr;
161469b9b88SMasami Hiramatsu 	int ret = -ENOENT;
1624b4da7f7SMasami Hiramatsu 
163469b9b88SMasami Hiramatsu 	sym = __find_kernel_function_by_name(tp->symbol, &map);
1644b4da7f7SMasami Hiramatsu 	if (sym) {
165469b9b88SMasami Hiramatsu 		addr = map->unmap_ip(map, sym->start + tp->offset);
166469b9b88SMasami Hiramatsu 		pr_debug("try to find %s+%ld@%llx\n", tp->symbol,
167469b9b88SMasami Hiramatsu 			 tp->offset, addr);
168469b9b88SMasami Hiramatsu 		ret = find_perf_probe_point((unsigned long)addr, pp);
169146a1439SMasami Hiramatsu 	}
1704b4da7f7SMasami Hiramatsu 	if (ret <= 0) {
171146a1439SMasami Hiramatsu 		pr_debug("Failed to find corresponding probes from "
172146a1439SMasami Hiramatsu 			 "debuginfo. Use kprobe event information.\n");
17302b95dadSMasami Hiramatsu 		pp->function = strdup(tp->symbol);
17402b95dadSMasami Hiramatsu 		if (pp->function == NULL)
17502b95dadSMasami Hiramatsu 			return -ENOMEM;
1764b4da7f7SMasami Hiramatsu 		pp->offset = tp->offset;
1774b4da7f7SMasami Hiramatsu 	}
1784b4da7f7SMasami Hiramatsu 	pp->retprobe = tp->retprobe;
179146a1439SMasami Hiramatsu 
180146a1439SMasami Hiramatsu 	return 0;
1814b4da7f7SMasami Hiramatsu }
1824b4da7f7SMasami Hiramatsu 
1834b4da7f7SMasami Hiramatsu /* Try to find perf_probe_event with debuginfo */
1840e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
1850e60836bSSrikar Dronamraju 					   struct probe_trace_event **tevs,
186469b9b88SMasami Hiramatsu 					   int max_tevs, const char *module)
1874b4da7f7SMasami Hiramatsu {
1884b4da7f7SMasami Hiramatsu 	bool need_dwarf = perf_probe_event_need_dwarf(pev);
1894b4da7f7SMasami Hiramatsu 	int fd, ntevs;
1904b4da7f7SMasami Hiramatsu 
191469b9b88SMasami Hiramatsu 	fd = open_vmlinux(module);
1924b4da7f7SMasami Hiramatsu 	if (fd < 0) {
193146a1439SMasami Hiramatsu 		if (need_dwarf) {
194146a1439SMasami Hiramatsu 			pr_warning("Failed to open debuginfo file.\n");
195146a1439SMasami Hiramatsu 			return fd;
196146a1439SMasami Hiramatsu 		}
1974b4da7f7SMasami Hiramatsu 		pr_debug("Could not open vmlinux. Try to use symbols.\n");
1984b4da7f7SMasami Hiramatsu 		return 0;
1994b4da7f7SMasami Hiramatsu 	}
2004b4da7f7SMasami Hiramatsu 
2014b4da7f7SMasami Hiramatsu 	/* Searching trace events corresponding to probe event */
2020e60836bSSrikar Dronamraju 	ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs);
2034b4da7f7SMasami Hiramatsu 	close(fd);
2044b4da7f7SMasami Hiramatsu 
205146a1439SMasami Hiramatsu 	if (ntevs > 0) {	/* Succeeded to find trace events */
2060e60836bSSrikar Dronamraju 		pr_debug("find %d probe_trace_events.\n", ntevs);
2074b4da7f7SMasami Hiramatsu 		return ntevs;
208146a1439SMasami Hiramatsu 	}
2094b4da7f7SMasami Hiramatsu 
210146a1439SMasami Hiramatsu 	if (ntevs == 0)	{	/* No error but failed to find probe point. */
211146a1439SMasami Hiramatsu 		pr_warning("Probe point '%s' not found.\n",
2124b4da7f7SMasami Hiramatsu 			   synthesize_perf_probe_point(&pev->point));
213146a1439SMasami Hiramatsu 		return -ENOENT;
214146a1439SMasami Hiramatsu 	}
215146a1439SMasami Hiramatsu 	/* Error path : ntevs < 0 */
21615eca306SMasami Hiramatsu 	pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
21715eca306SMasami Hiramatsu 	if (ntevs == -EBADF) {
21815eca306SMasami Hiramatsu 		pr_warning("Warning: No dwarf info found in the vmlinux - "
21915eca306SMasami Hiramatsu 			"please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
22015eca306SMasami Hiramatsu 		if (!need_dwarf) {
2210e43e5d2SMasami Hiramatsu 			pr_debug("Trying to use symbols.\n");
2224b4da7f7SMasami Hiramatsu 			return 0;
2234b4da7f7SMasami Hiramatsu 		}
22415eca306SMasami Hiramatsu 	}
22515eca306SMasami Hiramatsu 	return ntevs;
22615eca306SMasami Hiramatsu }
2274b4da7f7SMasami Hiramatsu 
2287cf0b79eSMasami Hiramatsu /*
2297cf0b79eSMasami Hiramatsu  * Find a src file from a DWARF tag path. Prepend optional source path prefix
2307cf0b79eSMasami Hiramatsu  * and chop off leading directories that do not exist. Result is passed back as
2317cf0b79eSMasami Hiramatsu  * a newly allocated path on success.
2327cf0b79eSMasami Hiramatsu  * Return 0 if file was found and readable, -errno otherwise.
2337cf0b79eSMasami Hiramatsu  */
2346a330a3cSMasami Hiramatsu static int get_real_path(const char *raw_path, const char *comp_dir,
2356a330a3cSMasami Hiramatsu 			 char **new_path)
2367cf0b79eSMasami Hiramatsu {
2376a330a3cSMasami Hiramatsu 	const char *prefix = symbol_conf.source_prefix;
2386a330a3cSMasami Hiramatsu 
2396a330a3cSMasami Hiramatsu 	if (!prefix) {
2406a330a3cSMasami Hiramatsu 		if (raw_path[0] != '/' && comp_dir)
2416a330a3cSMasami Hiramatsu 			/* If not an absolute path, try to use comp_dir */
2426a330a3cSMasami Hiramatsu 			prefix = comp_dir;
2436a330a3cSMasami Hiramatsu 		else {
2447cf0b79eSMasami Hiramatsu 			if (access(raw_path, R_OK) == 0) {
2457cf0b79eSMasami Hiramatsu 				*new_path = strdup(raw_path);
2467cf0b79eSMasami Hiramatsu 				return 0;
2477cf0b79eSMasami Hiramatsu 			} else
2487cf0b79eSMasami Hiramatsu 				return -errno;
2497cf0b79eSMasami Hiramatsu 		}
2506a330a3cSMasami Hiramatsu 	}
2517cf0b79eSMasami Hiramatsu 
2526a330a3cSMasami Hiramatsu 	*new_path = malloc((strlen(prefix) + strlen(raw_path) + 2));
2537cf0b79eSMasami Hiramatsu 	if (!*new_path)
2547cf0b79eSMasami Hiramatsu 		return -ENOMEM;
2557cf0b79eSMasami Hiramatsu 
2567cf0b79eSMasami Hiramatsu 	for (;;) {
2576a330a3cSMasami Hiramatsu 		sprintf(*new_path, "%s/%s", prefix, raw_path);
2587cf0b79eSMasami Hiramatsu 
2597cf0b79eSMasami Hiramatsu 		if (access(*new_path, R_OK) == 0)
2607cf0b79eSMasami Hiramatsu 			return 0;
2617cf0b79eSMasami Hiramatsu 
2626a330a3cSMasami Hiramatsu 		if (!symbol_conf.source_prefix)
2636a330a3cSMasami Hiramatsu 			/* In case of searching comp_dir, don't retry */
2646a330a3cSMasami Hiramatsu 			return -errno;
2656a330a3cSMasami Hiramatsu 
2667cf0b79eSMasami Hiramatsu 		switch (errno) {
2677cf0b79eSMasami Hiramatsu 		case ENAMETOOLONG:
2687cf0b79eSMasami Hiramatsu 		case ENOENT:
2697cf0b79eSMasami Hiramatsu 		case EROFS:
2707cf0b79eSMasami Hiramatsu 		case EFAULT:
2717cf0b79eSMasami Hiramatsu 			raw_path = strchr(++raw_path, '/');
2727cf0b79eSMasami Hiramatsu 			if (!raw_path) {
2737cf0b79eSMasami Hiramatsu 				free(*new_path);
2747cf0b79eSMasami Hiramatsu 				*new_path = NULL;
2757cf0b79eSMasami Hiramatsu 				return -ENOENT;
2767cf0b79eSMasami Hiramatsu 			}
2777cf0b79eSMasami Hiramatsu 			continue;
2787cf0b79eSMasami Hiramatsu 
2797cf0b79eSMasami Hiramatsu 		default:
2807cf0b79eSMasami Hiramatsu 			free(*new_path);
2817cf0b79eSMasami Hiramatsu 			*new_path = NULL;
2827cf0b79eSMasami Hiramatsu 			return -errno;
2837cf0b79eSMasami Hiramatsu 		}
2847cf0b79eSMasami Hiramatsu 	}
2857cf0b79eSMasami Hiramatsu }
2867cf0b79eSMasami Hiramatsu 
2874b4da7f7SMasami Hiramatsu #define LINEBUF_SIZE 256
2884b4da7f7SMasami Hiramatsu #define NR_ADDITIONAL_LINES 2
2894b4da7f7SMasami Hiramatsu 
290d3b63d7aSMasami Hiramatsu static int show_one_line(FILE *fp, int l, bool skip, bool show_num)
2914b4da7f7SMasami Hiramatsu {
2924b4da7f7SMasami Hiramatsu 	char buf[LINEBUF_SIZE];
2934b4da7f7SMasami Hiramatsu 	const char *color = PERF_COLOR_BLUE;
2944b4da7f7SMasami Hiramatsu 
2954b4da7f7SMasami Hiramatsu 	if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
2964b4da7f7SMasami Hiramatsu 		goto error;
2974b4da7f7SMasami Hiramatsu 	if (!skip) {
2984b4da7f7SMasami Hiramatsu 		if (show_num)
299d3b63d7aSMasami Hiramatsu 			fprintf(stdout, "%7d  %s", l, buf);
3004b4da7f7SMasami Hiramatsu 		else
3014b4da7f7SMasami Hiramatsu 			color_fprintf(stdout, color, "         %s", buf);
3024b4da7f7SMasami Hiramatsu 	}
3034b4da7f7SMasami Hiramatsu 
3044b4da7f7SMasami Hiramatsu 	while (strlen(buf) == LINEBUF_SIZE - 1 &&
3054b4da7f7SMasami Hiramatsu 	       buf[LINEBUF_SIZE - 2] != '\n') {
3064b4da7f7SMasami Hiramatsu 		if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
3074b4da7f7SMasami Hiramatsu 			goto error;
3084b4da7f7SMasami Hiramatsu 		if (!skip) {
3094b4da7f7SMasami Hiramatsu 			if (show_num)
3104b4da7f7SMasami Hiramatsu 				fprintf(stdout, "%s", buf);
3114b4da7f7SMasami Hiramatsu 			else
3124b4da7f7SMasami Hiramatsu 				color_fprintf(stdout, color, "%s", buf);
3134b4da7f7SMasami Hiramatsu 		}
3144b4da7f7SMasami Hiramatsu 	}
315146a1439SMasami Hiramatsu 
316146a1439SMasami Hiramatsu 	return 0;
3174b4da7f7SMasami Hiramatsu error:
3184b4da7f7SMasami Hiramatsu 	if (feof(fp))
319146a1439SMasami Hiramatsu 		pr_warning("Source file is shorter than expected.\n");
3204b4da7f7SMasami Hiramatsu 	else
321146a1439SMasami Hiramatsu 		pr_warning("File read error: %s\n", strerror(errno));
322146a1439SMasami Hiramatsu 
323146a1439SMasami Hiramatsu 	return -1;
3244b4da7f7SMasami Hiramatsu }
3254b4da7f7SMasami Hiramatsu 
3264b4da7f7SMasami Hiramatsu /*
3274b4da7f7SMasami Hiramatsu  * Show line-range always requires debuginfo to find source file and
3284b4da7f7SMasami Hiramatsu  * line number.
3294b4da7f7SMasami Hiramatsu  */
330469b9b88SMasami Hiramatsu int show_line_range(struct line_range *lr, const char *module)
3314b4da7f7SMasami Hiramatsu {
332d3b63d7aSMasami Hiramatsu 	int l = 1;
3334b4da7f7SMasami Hiramatsu 	struct line_node *ln;
3344b4da7f7SMasami Hiramatsu 	FILE *fp;
3354b4da7f7SMasami Hiramatsu 	int fd, ret;
3367cf0b79eSMasami Hiramatsu 	char *tmp;
3374b4da7f7SMasami Hiramatsu 
3384b4da7f7SMasami Hiramatsu 	/* Search a line range */
339146a1439SMasami Hiramatsu 	ret = init_vmlinux();
340146a1439SMasami Hiramatsu 	if (ret < 0)
341146a1439SMasami Hiramatsu 		return ret;
342146a1439SMasami Hiramatsu 
343469b9b88SMasami Hiramatsu 	fd = open_vmlinux(module);
344146a1439SMasami Hiramatsu 	if (fd < 0) {
345146a1439SMasami Hiramatsu 		pr_warning("Failed to open debuginfo file.\n");
346146a1439SMasami Hiramatsu 		return fd;
347146a1439SMasami Hiramatsu 	}
348146a1439SMasami Hiramatsu 
3494b4da7f7SMasami Hiramatsu 	ret = find_line_range(fd, lr);
3504b4da7f7SMasami Hiramatsu 	close(fd);
351146a1439SMasami Hiramatsu 	if (ret == 0) {
352146a1439SMasami Hiramatsu 		pr_warning("Specified source line is not found.\n");
353146a1439SMasami Hiramatsu 		return -ENOENT;
354146a1439SMasami Hiramatsu 	} else if (ret < 0) {
355146a1439SMasami Hiramatsu 		pr_warning("Debuginfo analysis failed. (%d)\n", ret);
356146a1439SMasami Hiramatsu 		return ret;
357146a1439SMasami Hiramatsu 	}
3584b4da7f7SMasami Hiramatsu 
3597cf0b79eSMasami Hiramatsu 	/* Convert source file path */
3607cf0b79eSMasami Hiramatsu 	tmp = lr->path;
3616a330a3cSMasami Hiramatsu 	ret = get_real_path(tmp, lr->comp_dir, &lr->path);
3627cf0b79eSMasami Hiramatsu 	free(tmp);	/* Free old path */
3637cf0b79eSMasami Hiramatsu 	if (ret < 0) {
3647cf0b79eSMasami Hiramatsu 		pr_warning("Failed to find source file. (%d)\n", ret);
3657cf0b79eSMasami Hiramatsu 		return ret;
3667cf0b79eSMasami Hiramatsu 	}
3677cf0b79eSMasami Hiramatsu 
3684b4da7f7SMasami Hiramatsu 	setup_pager();
3694b4da7f7SMasami Hiramatsu 
3704b4da7f7SMasami Hiramatsu 	if (lr->function)
3714b4da7f7SMasami Hiramatsu 		fprintf(stdout, "<%s:%d>\n", lr->function,
3724b4da7f7SMasami Hiramatsu 			lr->start - lr->offset);
3734b4da7f7SMasami Hiramatsu 	else
374*62c15fc4SFranck Bui-Huu 		fprintf(stdout, "<%s:%d>\n", lr->path, lr->start);
3754b4da7f7SMasami Hiramatsu 
3764b4da7f7SMasami Hiramatsu 	fp = fopen(lr->path, "r");
377146a1439SMasami Hiramatsu 	if (fp == NULL) {
378146a1439SMasami Hiramatsu 		pr_warning("Failed to open %s: %s\n", lr->path,
379146a1439SMasami Hiramatsu 			   strerror(errno));
380146a1439SMasami Hiramatsu 		return -errno;
381146a1439SMasami Hiramatsu 	}
3824b4da7f7SMasami Hiramatsu 	/* Skip to starting line number */
383146a1439SMasami Hiramatsu 	while (l < lr->start && ret >= 0)
384146a1439SMasami Hiramatsu 		ret = show_one_line(fp, l++, true, false);
385146a1439SMasami Hiramatsu 	if (ret < 0)
386146a1439SMasami Hiramatsu 		goto end;
3874b4da7f7SMasami Hiramatsu 
3884b4da7f7SMasami Hiramatsu 	list_for_each_entry(ln, &lr->line_list, list) {
389146a1439SMasami Hiramatsu 		while (ln->line > l && ret >= 0)
390146a1439SMasami Hiramatsu 			ret = show_one_line(fp, (l++) - lr->offset,
391146a1439SMasami Hiramatsu 					    false, false);
392146a1439SMasami Hiramatsu 		if (ret >= 0)
393146a1439SMasami Hiramatsu 			ret = show_one_line(fp, (l++) - lr->offset,
394146a1439SMasami Hiramatsu 					    false, true);
395146a1439SMasami Hiramatsu 		if (ret < 0)
396146a1439SMasami Hiramatsu 			goto end;
3974b4da7f7SMasami Hiramatsu 	}
3984b4da7f7SMasami Hiramatsu 
3994b4da7f7SMasami Hiramatsu 	if (lr->end == INT_MAX)
4004b4da7f7SMasami Hiramatsu 		lr->end = l + NR_ADDITIONAL_LINES;
401dda4ab34SMasami Hiramatsu 	while (l <= lr->end && !feof(fp) && ret >= 0)
402146a1439SMasami Hiramatsu 		ret = show_one_line(fp, (l++) - lr->offset, false, false);
403146a1439SMasami Hiramatsu end:
4044b4da7f7SMasami Hiramatsu 	fclose(fp);
405146a1439SMasami Hiramatsu 	return ret;
4064b4da7f7SMasami Hiramatsu }
4074b4da7f7SMasami Hiramatsu 
408cf6eb489SMasami Hiramatsu static int show_available_vars_at(int fd, struct perf_probe_event *pev,
409fb8c5a56SMasami Hiramatsu 				  int max_vls, bool externs)
410cf6eb489SMasami Hiramatsu {
411cf6eb489SMasami Hiramatsu 	char *buf;
412cf6eb489SMasami Hiramatsu 	int ret, i;
413cf6eb489SMasami Hiramatsu 	struct str_node *node;
414cf6eb489SMasami Hiramatsu 	struct variable_list *vls = NULL, *vl;
415cf6eb489SMasami Hiramatsu 
416cf6eb489SMasami Hiramatsu 	buf = synthesize_perf_probe_point(&pev->point);
417cf6eb489SMasami Hiramatsu 	if (!buf)
418cf6eb489SMasami Hiramatsu 		return -EINVAL;
419cf6eb489SMasami Hiramatsu 	pr_debug("Searching variables at %s\n", buf);
420cf6eb489SMasami Hiramatsu 
421fb8c5a56SMasami Hiramatsu 	ret = find_available_vars_at(fd, pev, &vls, max_vls, externs);
422cf6eb489SMasami Hiramatsu 	if (ret > 0) {
423cf6eb489SMasami Hiramatsu 		/* Some variables were found */
424cf6eb489SMasami Hiramatsu 		fprintf(stdout, "Available variables at %s\n", buf);
425cf6eb489SMasami Hiramatsu 		for (i = 0; i < ret; i++) {
426cf6eb489SMasami Hiramatsu 			vl = &vls[i];
427cf6eb489SMasami Hiramatsu 			/*
428cf6eb489SMasami Hiramatsu 			 * A probe point might be converted to
429cf6eb489SMasami Hiramatsu 			 * several trace points.
430cf6eb489SMasami Hiramatsu 			 */
431cf6eb489SMasami Hiramatsu 			fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
432cf6eb489SMasami Hiramatsu 				vl->point.offset);
433cf6eb489SMasami Hiramatsu 			free(vl->point.symbol);
434cf6eb489SMasami Hiramatsu 			if (vl->vars) {
435cf6eb489SMasami Hiramatsu 				strlist__for_each(node, vl->vars)
436cf6eb489SMasami Hiramatsu 					fprintf(stdout, "\t\t%s\n", node->s);
437cf6eb489SMasami Hiramatsu 				strlist__delete(vl->vars);
438cf6eb489SMasami Hiramatsu 			} else
439cf6eb489SMasami Hiramatsu 				fprintf(stdout, "(No variables)\n");
440cf6eb489SMasami Hiramatsu 		}
441cf6eb489SMasami Hiramatsu 		free(vls);
442cf6eb489SMasami Hiramatsu 	} else
443cf6eb489SMasami Hiramatsu 		pr_err("Failed to find variables at %s (%d)\n", buf, ret);
444cf6eb489SMasami Hiramatsu 
445cf6eb489SMasami Hiramatsu 	free(buf);
446cf6eb489SMasami Hiramatsu 	return ret;
447cf6eb489SMasami Hiramatsu }
448cf6eb489SMasami Hiramatsu 
449cf6eb489SMasami Hiramatsu /* Show available variables on given probe point */
450cf6eb489SMasami Hiramatsu int show_available_vars(struct perf_probe_event *pevs, int npevs,
451469b9b88SMasami Hiramatsu 			int max_vls, const char *module, bool externs)
452cf6eb489SMasami Hiramatsu {
453cf6eb489SMasami Hiramatsu 	int i, fd, ret = 0;
454cf6eb489SMasami Hiramatsu 
455cf6eb489SMasami Hiramatsu 	ret = init_vmlinux();
456cf6eb489SMasami Hiramatsu 	if (ret < 0)
457cf6eb489SMasami Hiramatsu 		return ret;
458cf6eb489SMasami Hiramatsu 
459469b9b88SMasami Hiramatsu 	fd = open_vmlinux(module);
460cf6eb489SMasami Hiramatsu 	if (fd < 0) {
4610e43e5d2SMasami Hiramatsu 		pr_warning("Failed to open debug information file.\n");
462cf6eb489SMasami Hiramatsu 		return fd;
463cf6eb489SMasami Hiramatsu 	}
464cf6eb489SMasami Hiramatsu 
465cf6eb489SMasami Hiramatsu 	setup_pager();
466cf6eb489SMasami Hiramatsu 
467cf6eb489SMasami Hiramatsu 	for (i = 0; i < npevs && ret >= 0; i++)
468fb8c5a56SMasami Hiramatsu 		ret = show_available_vars_at(fd, &pevs[i], max_vls, externs);
469cf6eb489SMasami Hiramatsu 
470cf6eb489SMasami Hiramatsu 	close(fd);
471cf6eb489SMasami Hiramatsu 	return ret;
472cf6eb489SMasami Hiramatsu }
473cf6eb489SMasami Hiramatsu 
4744b4da7f7SMasami Hiramatsu #else	/* !DWARF_SUPPORT */
4754b4da7f7SMasami Hiramatsu 
4760e60836bSSrikar Dronamraju static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
4774b4da7f7SMasami Hiramatsu 					struct perf_probe_point *pp)
4784b4da7f7SMasami Hiramatsu {
479469b9b88SMasami Hiramatsu 	struct symbol *sym;
480469b9b88SMasami Hiramatsu 
481469b9b88SMasami Hiramatsu 	sym = __find_kernel_function_by_name(tp->symbol, NULL);
482469b9b88SMasami Hiramatsu 	if (!sym) {
483469b9b88SMasami Hiramatsu 		pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
484469b9b88SMasami Hiramatsu 		return -ENOENT;
485469b9b88SMasami Hiramatsu 	}
48602b95dadSMasami Hiramatsu 	pp->function = strdup(tp->symbol);
48702b95dadSMasami Hiramatsu 	if (pp->function == NULL)
48802b95dadSMasami Hiramatsu 		return -ENOMEM;
4894b4da7f7SMasami Hiramatsu 	pp->offset = tp->offset;
4904b4da7f7SMasami Hiramatsu 	pp->retprobe = tp->retprobe;
491146a1439SMasami Hiramatsu 
492146a1439SMasami Hiramatsu 	return 0;
4934b4da7f7SMasami Hiramatsu }
4944b4da7f7SMasami Hiramatsu 
4950e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
4960e60836bSSrikar Dronamraju 				struct probe_trace_event **tevs __unused,
497469b9b88SMasami Hiramatsu 				int max_tevs __unused, const char *mod __unused)
4984b4da7f7SMasami Hiramatsu {
499146a1439SMasami Hiramatsu 	if (perf_probe_event_need_dwarf(pev)) {
500146a1439SMasami Hiramatsu 		pr_warning("Debuginfo-analysis is not supported.\n");
501146a1439SMasami Hiramatsu 		return -ENOSYS;
502146a1439SMasami Hiramatsu 	}
5034b4da7f7SMasami Hiramatsu 	return 0;
5044b4da7f7SMasami Hiramatsu }
5054b4da7f7SMasami Hiramatsu 
506469b9b88SMasami Hiramatsu int show_line_range(struct line_range *lr __unused, const char *module __unused)
5074b4da7f7SMasami Hiramatsu {
508146a1439SMasami Hiramatsu 	pr_warning("Debuginfo-analysis is not supported.\n");
509146a1439SMasami Hiramatsu 	return -ENOSYS;
5104b4da7f7SMasami Hiramatsu }
5114b4da7f7SMasami Hiramatsu 
512cf6eb489SMasami Hiramatsu int show_available_vars(struct perf_probe_event *pevs __unused,
513469b9b88SMasami Hiramatsu 			int npevs __unused, int max_vls __unused,
514469b9b88SMasami Hiramatsu 			const char *module __unused, bool externs __unused)
515cf6eb489SMasami Hiramatsu {
516cf6eb489SMasami Hiramatsu 	pr_warning("Debuginfo-analysis is not supported.\n");
517cf6eb489SMasami Hiramatsu 	return -ENOSYS;
518cf6eb489SMasami Hiramatsu }
519e0faa8d3SMasami Hiramatsu #endif
520e0faa8d3SMasami Hiramatsu 
521146a1439SMasami Hiramatsu int parse_line_range_desc(const char *arg, struct line_range *lr)
522631c9defSMasami Hiramatsu {
523631c9defSMasami Hiramatsu 	const char *ptr;
524631c9defSMasami Hiramatsu 	char *tmp;
525631c9defSMasami Hiramatsu 	/*
526631c9defSMasami Hiramatsu 	 * <Syntax>
527631c9defSMasami Hiramatsu 	 * SRC:SLN[+NUM|-ELN]
528631c9defSMasami Hiramatsu 	 * FUNC[:SLN[+NUM|-ELN]]
529631c9defSMasami Hiramatsu 	 */
530631c9defSMasami Hiramatsu 	ptr = strchr(arg, ':');
531631c9defSMasami Hiramatsu 	if (ptr) {
532d3b63d7aSMasami Hiramatsu 		lr->start = (int)strtoul(ptr + 1, &tmp, 0);
533dda4ab34SMasami Hiramatsu 		if (*tmp == '+') {
534d3b63d7aSMasami Hiramatsu 			lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0);
535dda4ab34SMasami Hiramatsu 			lr->end--;	/*
536dda4ab34SMasami Hiramatsu 					 * Adjust the number of lines here.
537dda4ab34SMasami Hiramatsu 					 * If the number of lines == 1, the
538dda4ab34SMasami Hiramatsu 					 * the end of line should be equal to
539dda4ab34SMasami Hiramatsu 					 * the start of line.
540dda4ab34SMasami Hiramatsu 					 */
541dda4ab34SMasami Hiramatsu 		} else if (*tmp == '-')
542d3b63d7aSMasami Hiramatsu 			lr->end = (int)strtoul(tmp + 1, &tmp, 0);
543631c9defSMasami Hiramatsu 		else
544d3b63d7aSMasami Hiramatsu 			lr->end = INT_MAX;
545d3b63d7aSMasami Hiramatsu 		pr_debug("Line range is %d to %d\n", lr->start, lr->end);
546d3b63d7aSMasami Hiramatsu 		if (lr->start > lr->end) {
547631c9defSMasami Hiramatsu 			semantic_error("Start line must be smaller"
548146a1439SMasami Hiramatsu 				       " than end line.\n");
549146a1439SMasami Hiramatsu 			return -EINVAL;
550146a1439SMasami Hiramatsu 		}
551146a1439SMasami Hiramatsu 		if (*tmp != '\0') {
552146a1439SMasami Hiramatsu 			semantic_error("Tailing with invalid character '%d'.\n",
553631c9defSMasami Hiramatsu 				       *tmp);
554146a1439SMasami Hiramatsu 			return -EINVAL;
555146a1439SMasami Hiramatsu 		}
55602b95dadSMasami Hiramatsu 		tmp = strndup(arg, (ptr - arg));
557d3b63d7aSMasami Hiramatsu 	} else {
55802b95dadSMasami Hiramatsu 		tmp = strdup(arg);
559d3b63d7aSMasami Hiramatsu 		lr->end = INT_MAX;
560d3b63d7aSMasami Hiramatsu 	}
56102b95dadSMasami Hiramatsu 
56202b95dadSMasami Hiramatsu 	if (tmp == NULL)
56302b95dadSMasami Hiramatsu 		return -ENOMEM;
564631c9defSMasami Hiramatsu 
565631c9defSMasami Hiramatsu 	if (strchr(tmp, '.'))
566631c9defSMasami Hiramatsu 		lr->file = tmp;
567631c9defSMasami Hiramatsu 	else
568631c9defSMasami Hiramatsu 		lr->function = tmp;
569146a1439SMasami Hiramatsu 
570146a1439SMasami Hiramatsu 	return 0;
571631c9defSMasami Hiramatsu }
572631c9defSMasami Hiramatsu 
573b7702a21SMasami Hiramatsu /* Check the name is good for event/group */
574b7702a21SMasami Hiramatsu static bool check_event_name(const char *name)
575b7702a21SMasami Hiramatsu {
576b7702a21SMasami Hiramatsu 	if (!isalpha(*name) && *name != '_')
577b7702a21SMasami Hiramatsu 		return false;
578b7702a21SMasami Hiramatsu 	while (*++name != '\0') {
579b7702a21SMasami Hiramatsu 		if (!isalpha(*name) && !isdigit(*name) && *name != '_')
580b7702a21SMasami Hiramatsu 			return false;
581b7702a21SMasami Hiramatsu 	}
582b7702a21SMasami Hiramatsu 	return true;
583b7702a21SMasami Hiramatsu }
584b7702a21SMasami Hiramatsu 
58550656eecSMasami Hiramatsu /* Parse probepoint definition. */
586146a1439SMasami Hiramatsu static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
58750656eecSMasami Hiramatsu {
5884235b045SMasami Hiramatsu 	struct perf_probe_point *pp = &pev->point;
58950656eecSMasami Hiramatsu 	char *ptr, *tmp;
59050656eecSMasami Hiramatsu 	char c, nc = 0;
59150656eecSMasami Hiramatsu 	/*
59250656eecSMasami Hiramatsu 	 * <Syntax>
5932a9c8c36SMasami Hiramatsu 	 * perf probe [EVENT=]SRC[:LN|;PTN]
5942a9c8c36SMasami Hiramatsu 	 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
595af663d75SMasami Hiramatsu 	 *
596af663d75SMasami Hiramatsu 	 * TODO:Group name support
59750656eecSMasami Hiramatsu 	 */
59850656eecSMasami Hiramatsu 
5992a9c8c36SMasami Hiramatsu 	ptr = strpbrk(arg, ";=@+%");
6002a9c8c36SMasami Hiramatsu 	if (ptr && *ptr == '=') {	/* Event name */
601af663d75SMasami Hiramatsu 		*ptr = '\0';
602af663d75SMasami Hiramatsu 		tmp = ptr + 1;
603146a1439SMasami Hiramatsu 		if (strchr(arg, ':')) {
604146a1439SMasami Hiramatsu 			semantic_error("Group name is not supported yet.\n");
605146a1439SMasami Hiramatsu 			return -ENOTSUP;
606146a1439SMasami Hiramatsu 		}
607146a1439SMasami Hiramatsu 		if (!check_event_name(arg)) {
608b7702a21SMasami Hiramatsu 			semantic_error("%s is bad for event name -it must "
609146a1439SMasami Hiramatsu 				       "follow C symbol-naming rule.\n", arg);
610146a1439SMasami Hiramatsu 			return -EINVAL;
611146a1439SMasami Hiramatsu 		}
61202b95dadSMasami Hiramatsu 		pev->event = strdup(arg);
61302b95dadSMasami Hiramatsu 		if (pev->event == NULL)
61402b95dadSMasami Hiramatsu 			return -ENOMEM;
6154235b045SMasami Hiramatsu 		pev->group = NULL;
616af663d75SMasami Hiramatsu 		arg = tmp;
617af663d75SMasami Hiramatsu 	}
618af663d75SMasami Hiramatsu 
6192a9c8c36SMasami Hiramatsu 	ptr = strpbrk(arg, ";:+@%");
62050656eecSMasami Hiramatsu 	if (ptr) {
62150656eecSMasami Hiramatsu 		nc = *ptr;
62250656eecSMasami Hiramatsu 		*ptr++ = '\0';
62350656eecSMasami Hiramatsu 	}
62450656eecSMasami Hiramatsu 
62502b95dadSMasami Hiramatsu 	tmp = strdup(arg);
62602b95dadSMasami Hiramatsu 	if (tmp == NULL)
62702b95dadSMasami Hiramatsu 		return -ENOMEM;
62802b95dadSMasami Hiramatsu 
62950656eecSMasami Hiramatsu 	/* Check arg is function or file and copy it */
63002b95dadSMasami Hiramatsu 	if (strchr(tmp, '.'))	/* File */
63102b95dadSMasami Hiramatsu 		pp->file = tmp;
63250656eecSMasami Hiramatsu 	else			/* Function */
63302b95dadSMasami Hiramatsu 		pp->function = tmp;
63450656eecSMasami Hiramatsu 
63550656eecSMasami Hiramatsu 	/* Parse other options */
63650656eecSMasami Hiramatsu 	while (ptr) {
63750656eecSMasami Hiramatsu 		arg = ptr;
63850656eecSMasami Hiramatsu 		c = nc;
6392a9c8c36SMasami Hiramatsu 		if (c == ';') {	/* Lazy pattern must be the last part */
64002b95dadSMasami Hiramatsu 			pp->lazy_line = strdup(arg);
64102b95dadSMasami Hiramatsu 			if (pp->lazy_line == NULL)
64202b95dadSMasami Hiramatsu 				return -ENOMEM;
6432a9c8c36SMasami Hiramatsu 			break;
6442a9c8c36SMasami Hiramatsu 		}
6452a9c8c36SMasami Hiramatsu 		ptr = strpbrk(arg, ";:+@%");
64650656eecSMasami Hiramatsu 		if (ptr) {
64750656eecSMasami Hiramatsu 			nc = *ptr;
64850656eecSMasami Hiramatsu 			*ptr++ = '\0';
64950656eecSMasami Hiramatsu 		}
65050656eecSMasami Hiramatsu 		switch (c) {
65150656eecSMasami Hiramatsu 		case ':':	/* Line number */
65250656eecSMasami Hiramatsu 			pp->line = strtoul(arg, &tmp, 0);
653146a1439SMasami Hiramatsu 			if (*tmp != '\0') {
6542a9c8c36SMasami Hiramatsu 				semantic_error("There is non-digit char"
655146a1439SMasami Hiramatsu 					       " in line number.\n");
656146a1439SMasami Hiramatsu 				return -EINVAL;
657146a1439SMasami Hiramatsu 			}
65850656eecSMasami Hiramatsu 			break;
65950656eecSMasami Hiramatsu 		case '+':	/* Byte offset from a symbol */
66050656eecSMasami Hiramatsu 			pp->offset = strtoul(arg, &tmp, 0);
661146a1439SMasami Hiramatsu 			if (*tmp != '\0') {
6622a9c8c36SMasami Hiramatsu 				semantic_error("There is non-digit character"
663146a1439SMasami Hiramatsu 						" in offset.\n");
664146a1439SMasami Hiramatsu 				return -EINVAL;
665146a1439SMasami Hiramatsu 			}
66650656eecSMasami Hiramatsu 			break;
66750656eecSMasami Hiramatsu 		case '@':	/* File name */
668146a1439SMasami Hiramatsu 			if (pp->file) {
669146a1439SMasami Hiramatsu 				semantic_error("SRC@SRC is not allowed.\n");
670146a1439SMasami Hiramatsu 				return -EINVAL;
671146a1439SMasami Hiramatsu 			}
67202b95dadSMasami Hiramatsu 			pp->file = strdup(arg);
67302b95dadSMasami Hiramatsu 			if (pp->file == NULL)
67402b95dadSMasami Hiramatsu 				return -ENOMEM;
67550656eecSMasami Hiramatsu 			break;
67650656eecSMasami Hiramatsu 		case '%':	/* Probe places */
67750656eecSMasami Hiramatsu 			if (strcmp(arg, "return") == 0) {
67850656eecSMasami Hiramatsu 				pp->retprobe = 1;
679146a1439SMasami Hiramatsu 			} else {	/* Others not supported yet */
680146a1439SMasami Hiramatsu 				semantic_error("%%%s is not supported.\n", arg);
681146a1439SMasami Hiramatsu 				return -ENOTSUP;
682146a1439SMasami Hiramatsu 			}
68350656eecSMasami Hiramatsu 			break;
684146a1439SMasami Hiramatsu 		default:	/* Buggy case */
685146a1439SMasami Hiramatsu 			pr_err("This program has a bug at %s:%d.\n",
686146a1439SMasami Hiramatsu 				__FILE__, __LINE__);
687146a1439SMasami Hiramatsu 			return -ENOTSUP;
68850656eecSMasami Hiramatsu 			break;
68950656eecSMasami Hiramatsu 		}
69050656eecSMasami Hiramatsu 	}
69150656eecSMasami Hiramatsu 
69250656eecSMasami Hiramatsu 	/* Exclusion check */
693146a1439SMasami Hiramatsu 	if (pp->lazy_line && pp->line) {
6940e43e5d2SMasami Hiramatsu 		semantic_error("Lazy pattern can't be used with"
6950e43e5d2SMasami Hiramatsu 			       " line number.\n");
696146a1439SMasami Hiramatsu 		return -EINVAL;
697146a1439SMasami Hiramatsu 	}
6982a9c8c36SMasami Hiramatsu 
699146a1439SMasami Hiramatsu 	if (pp->lazy_line && pp->offset) {
7000e43e5d2SMasami Hiramatsu 		semantic_error("Lazy pattern can't be used with offset.\n");
701146a1439SMasami Hiramatsu 		return -EINVAL;
702146a1439SMasami Hiramatsu 	}
7032a9c8c36SMasami Hiramatsu 
704146a1439SMasami Hiramatsu 	if (pp->line && pp->offset) {
7050e43e5d2SMasami Hiramatsu 		semantic_error("Offset can't be used with line number.\n");
706146a1439SMasami Hiramatsu 		return -EINVAL;
707146a1439SMasami Hiramatsu 	}
70850656eecSMasami Hiramatsu 
709146a1439SMasami Hiramatsu 	if (!pp->line && !pp->lazy_line && pp->file && !pp->function) {
7102a9c8c36SMasami Hiramatsu 		semantic_error("File always requires line number or "
7110e43e5d2SMasami Hiramatsu 			       "lazy pattern.\n");
712146a1439SMasami Hiramatsu 		return -EINVAL;
713146a1439SMasami Hiramatsu 	}
71450656eecSMasami Hiramatsu 
715146a1439SMasami Hiramatsu 	if (pp->offset && !pp->function) {
7160e43e5d2SMasami Hiramatsu 		semantic_error("Offset requires an entry function.\n");
717146a1439SMasami Hiramatsu 		return -EINVAL;
718146a1439SMasami Hiramatsu 	}
71950656eecSMasami Hiramatsu 
720146a1439SMasami Hiramatsu 	if (pp->retprobe && !pp->function) {
7210e43e5d2SMasami Hiramatsu 		semantic_error("Return probe requires an entry function.\n");
722146a1439SMasami Hiramatsu 		return -EINVAL;
723146a1439SMasami Hiramatsu 	}
72450656eecSMasami Hiramatsu 
725146a1439SMasami Hiramatsu 	if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
7262a9c8c36SMasami Hiramatsu 		semantic_error("Offset/Line/Lazy pattern can't be used with "
7270e43e5d2SMasami Hiramatsu 			       "return probe.\n");
728146a1439SMasami Hiramatsu 		return -EINVAL;
729146a1439SMasami Hiramatsu 	}
73050656eecSMasami Hiramatsu 
7314235b045SMasami Hiramatsu 	pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
7322a9c8c36SMasami Hiramatsu 		 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
7332a9c8c36SMasami Hiramatsu 		 pp->lazy_line);
734146a1439SMasami Hiramatsu 	return 0;
73550656eecSMasami Hiramatsu }
73650656eecSMasami Hiramatsu 
7377df2f329SMasami Hiramatsu /* Parse perf-probe event argument */
738146a1439SMasami Hiramatsu static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
7397df2f329SMasami Hiramatsu {
740b2a3c12bSMasami Hiramatsu 	char *tmp, *goodname;
7417df2f329SMasami Hiramatsu 	struct perf_probe_arg_field **fieldp;
7427df2f329SMasami Hiramatsu 
7437df2f329SMasami Hiramatsu 	pr_debug("parsing arg: %s into ", str);
7447df2f329SMasami Hiramatsu 
74548481938SMasami Hiramatsu 	tmp = strchr(str, '=');
74648481938SMasami Hiramatsu 	if (tmp) {
74702b95dadSMasami Hiramatsu 		arg->name = strndup(str, tmp - str);
74802b95dadSMasami Hiramatsu 		if (arg->name == NULL)
74902b95dadSMasami Hiramatsu 			return -ENOMEM;
75011a1ca35SMasami Hiramatsu 		pr_debug("name:%s ", arg->name);
75148481938SMasami Hiramatsu 		str = tmp + 1;
75248481938SMasami Hiramatsu 	}
75348481938SMasami Hiramatsu 
75411a1ca35SMasami Hiramatsu 	tmp = strchr(str, ':');
75511a1ca35SMasami Hiramatsu 	if (tmp) {	/* Type setting */
75611a1ca35SMasami Hiramatsu 		*tmp = '\0';
75702b95dadSMasami Hiramatsu 		arg->type = strdup(tmp + 1);
75802b95dadSMasami Hiramatsu 		if (arg->type == NULL)
75902b95dadSMasami Hiramatsu 			return -ENOMEM;
76011a1ca35SMasami Hiramatsu 		pr_debug("type:%s ", arg->type);
76111a1ca35SMasami Hiramatsu 	}
76211a1ca35SMasami Hiramatsu 
763b2a3c12bSMasami Hiramatsu 	tmp = strpbrk(str, "-.[");
7647df2f329SMasami Hiramatsu 	if (!is_c_varname(str) || !tmp) {
7657df2f329SMasami Hiramatsu 		/* A variable, register, symbol or special value */
76602b95dadSMasami Hiramatsu 		arg->var = strdup(str);
76702b95dadSMasami Hiramatsu 		if (arg->var == NULL)
76802b95dadSMasami Hiramatsu 			return -ENOMEM;
76948481938SMasami Hiramatsu 		pr_debug("%s\n", arg->var);
770146a1439SMasami Hiramatsu 		return 0;
7717df2f329SMasami Hiramatsu 	}
7727df2f329SMasami Hiramatsu 
773b2a3c12bSMasami Hiramatsu 	/* Structure fields or array element */
77402b95dadSMasami Hiramatsu 	arg->var = strndup(str, tmp - str);
77502b95dadSMasami Hiramatsu 	if (arg->var == NULL)
77602b95dadSMasami Hiramatsu 		return -ENOMEM;
777b2a3c12bSMasami Hiramatsu 	goodname = arg->var;
77848481938SMasami Hiramatsu 	pr_debug("%s, ", arg->var);
7797df2f329SMasami Hiramatsu 	fieldp = &arg->field;
7807df2f329SMasami Hiramatsu 
7817df2f329SMasami Hiramatsu 	do {
782e334016fSMasami Hiramatsu 		*fieldp = zalloc(sizeof(struct perf_probe_arg_field));
783e334016fSMasami Hiramatsu 		if (*fieldp == NULL)
784e334016fSMasami Hiramatsu 			return -ENOMEM;
785b2a3c12bSMasami Hiramatsu 		if (*tmp == '[') {	/* Array */
786b2a3c12bSMasami Hiramatsu 			str = tmp;
787b2a3c12bSMasami Hiramatsu 			(*fieldp)->index = strtol(str + 1, &tmp, 0);
788b2a3c12bSMasami Hiramatsu 			(*fieldp)->ref = true;
789b2a3c12bSMasami Hiramatsu 			if (*tmp != ']' || tmp == str + 1) {
790b2a3c12bSMasami Hiramatsu 				semantic_error("Array index must be a"
791b2a3c12bSMasami Hiramatsu 						" number.\n");
792b2a3c12bSMasami Hiramatsu 				return -EINVAL;
793b2a3c12bSMasami Hiramatsu 			}
794b2a3c12bSMasami Hiramatsu 			tmp++;
795b2a3c12bSMasami Hiramatsu 			if (*tmp == '\0')
796b2a3c12bSMasami Hiramatsu 				tmp = NULL;
797b2a3c12bSMasami Hiramatsu 		} else {		/* Structure */
7987df2f329SMasami Hiramatsu 			if (*tmp == '.') {
7997df2f329SMasami Hiramatsu 				str = tmp + 1;
8007df2f329SMasami Hiramatsu 				(*fieldp)->ref = false;
8017df2f329SMasami Hiramatsu 			} else if (tmp[1] == '>') {
8027df2f329SMasami Hiramatsu 				str = tmp + 2;
8037df2f329SMasami Hiramatsu 				(*fieldp)->ref = true;
804146a1439SMasami Hiramatsu 			} else {
805b2a3c12bSMasami Hiramatsu 				semantic_error("Argument parse error: %s\n",
806b2a3c12bSMasami Hiramatsu 					       str);
807146a1439SMasami Hiramatsu 				return -EINVAL;
808146a1439SMasami Hiramatsu 			}
809b2a3c12bSMasami Hiramatsu 			tmp = strpbrk(str, "-.[");
810b2a3c12bSMasami Hiramatsu 		}
8117df2f329SMasami Hiramatsu 		if (tmp) {
81202b95dadSMasami Hiramatsu 			(*fieldp)->name = strndup(str, tmp - str);
81302b95dadSMasami Hiramatsu 			if ((*fieldp)->name == NULL)
81402b95dadSMasami Hiramatsu 				return -ENOMEM;
815b2a3c12bSMasami Hiramatsu 			if (*str != '[')
816b2a3c12bSMasami Hiramatsu 				goodname = (*fieldp)->name;
8177df2f329SMasami Hiramatsu 			pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
8187df2f329SMasami Hiramatsu 			fieldp = &(*fieldp)->next;
8197df2f329SMasami Hiramatsu 		}
8207df2f329SMasami Hiramatsu 	} while (tmp);
82102b95dadSMasami Hiramatsu 	(*fieldp)->name = strdup(str);
82202b95dadSMasami Hiramatsu 	if ((*fieldp)->name == NULL)
82302b95dadSMasami Hiramatsu 		return -ENOMEM;
824b2a3c12bSMasami Hiramatsu 	if (*str != '[')
825b2a3c12bSMasami Hiramatsu 		goodname = (*fieldp)->name;
8267df2f329SMasami Hiramatsu 	pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
827df0faf4bSMasami Hiramatsu 
828b2a3c12bSMasami Hiramatsu 	/* If no name is specified, set the last field name (not array index)*/
82902b95dadSMasami Hiramatsu 	if (!arg->name) {
830b2a3c12bSMasami Hiramatsu 		arg->name = strdup(goodname);
83102b95dadSMasami Hiramatsu 		if (arg->name == NULL)
83202b95dadSMasami Hiramatsu 			return -ENOMEM;
83302b95dadSMasami Hiramatsu 	}
834146a1439SMasami Hiramatsu 	return 0;
8357df2f329SMasami Hiramatsu }
8367df2f329SMasami Hiramatsu 
8374235b045SMasami Hiramatsu /* Parse perf-probe event command */
838146a1439SMasami Hiramatsu int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
83950656eecSMasami Hiramatsu {
840e1c01d61SMasami Hiramatsu 	char **argv;
841146a1439SMasami Hiramatsu 	int argc, i, ret = 0;
842fac13fd5SMasami Hiramatsu 
8434235b045SMasami Hiramatsu 	argv = argv_split(cmd, &argc);
844146a1439SMasami Hiramatsu 	if (!argv) {
845146a1439SMasami Hiramatsu 		pr_debug("Failed to split arguments.\n");
846146a1439SMasami Hiramatsu 		return -ENOMEM;
847146a1439SMasami Hiramatsu 	}
848146a1439SMasami Hiramatsu 	if (argc - 1 > MAX_PROBE_ARGS) {
849146a1439SMasami Hiramatsu 		semantic_error("Too many probe arguments (%d).\n", argc - 1);
850146a1439SMasami Hiramatsu 		ret = -ERANGE;
851146a1439SMasami Hiramatsu 		goto out;
852146a1439SMasami Hiramatsu 	}
85350656eecSMasami Hiramatsu 	/* Parse probe point */
854146a1439SMasami Hiramatsu 	ret = parse_perf_probe_point(argv[0], pev);
855146a1439SMasami Hiramatsu 	if (ret < 0)
856146a1439SMasami Hiramatsu 		goto out;
85750656eecSMasami Hiramatsu 
858e1c01d61SMasami Hiramatsu 	/* Copy arguments and ensure return probe has no C argument */
8594235b045SMasami Hiramatsu 	pev->nargs = argc - 1;
860e334016fSMasami Hiramatsu 	pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
861e334016fSMasami Hiramatsu 	if (pev->args == NULL) {
862e334016fSMasami Hiramatsu 		ret = -ENOMEM;
863e334016fSMasami Hiramatsu 		goto out;
864e334016fSMasami Hiramatsu 	}
865146a1439SMasami Hiramatsu 	for (i = 0; i < pev->nargs && ret >= 0; i++) {
866146a1439SMasami Hiramatsu 		ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]);
867146a1439SMasami Hiramatsu 		if (ret >= 0 &&
868146a1439SMasami Hiramatsu 		    is_c_varname(pev->args[i].var) && pev->point.retprobe) {
8694235b045SMasami Hiramatsu 			semantic_error("You can't specify local variable for"
870146a1439SMasami Hiramatsu 				       " kretprobe.\n");
871146a1439SMasami Hiramatsu 			ret = -EINVAL;
872e1c01d61SMasami Hiramatsu 		}
873146a1439SMasami Hiramatsu 	}
874146a1439SMasami Hiramatsu out:
875e1c01d61SMasami Hiramatsu 	argv_free(argv);
876146a1439SMasami Hiramatsu 
877146a1439SMasami Hiramatsu 	return ret;
87850656eecSMasami Hiramatsu }
87950656eecSMasami Hiramatsu 
8804235b045SMasami Hiramatsu /* Return true if this perf_probe_event requires debuginfo */
8814235b045SMasami Hiramatsu bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
8824de189feSMasami Hiramatsu {
8834235b045SMasami Hiramatsu 	int i;
8844235b045SMasami Hiramatsu 
8854235b045SMasami Hiramatsu 	if (pev->point.file || pev->point.line || pev->point.lazy_line)
8864235b045SMasami Hiramatsu 		return true;
8874235b045SMasami Hiramatsu 
8884235b045SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++)
88948481938SMasami Hiramatsu 		if (is_c_varname(pev->args[i].var))
8904235b045SMasami Hiramatsu 			return true;
8914235b045SMasami Hiramatsu 
8924235b045SMasami Hiramatsu 	return false;
8934235b045SMasami Hiramatsu }
8944235b045SMasami Hiramatsu 
8950e60836bSSrikar Dronamraju /* Parse probe_events event into struct probe_point */
8960e60836bSSrikar Dronamraju static int parse_probe_trace_command(const char *cmd,
8970e60836bSSrikar Dronamraju 					struct probe_trace_event *tev)
8984235b045SMasami Hiramatsu {
8990e60836bSSrikar Dronamraju 	struct probe_trace_point *tp = &tev->point;
9004de189feSMasami Hiramatsu 	char pr;
9014de189feSMasami Hiramatsu 	char *p;
9024de189feSMasami Hiramatsu 	int ret, i, argc;
9034de189feSMasami Hiramatsu 	char **argv;
9044de189feSMasami Hiramatsu 
9050e60836bSSrikar Dronamraju 	pr_debug("Parsing probe_events: %s\n", cmd);
9064235b045SMasami Hiramatsu 	argv = argv_split(cmd, &argc);
907146a1439SMasami Hiramatsu 	if (!argv) {
908146a1439SMasami Hiramatsu 		pr_debug("Failed to split arguments.\n");
909146a1439SMasami Hiramatsu 		return -ENOMEM;
910146a1439SMasami Hiramatsu 	}
911146a1439SMasami Hiramatsu 	if (argc < 2) {
912146a1439SMasami Hiramatsu 		semantic_error("Too few probe arguments.\n");
913146a1439SMasami Hiramatsu 		ret = -ERANGE;
914146a1439SMasami Hiramatsu 		goto out;
915146a1439SMasami Hiramatsu 	}
9164de189feSMasami Hiramatsu 
9174de189feSMasami Hiramatsu 	/* Scan event and group name. */
91893aaa45aSLiming Wang 	ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
9194235b045SMasami Hiramatsu 		     &pr, (float *)(void *)&tev->group,
9204235b045SMasami Hiramatsu 		     (float *)(void *)&tev->event);
921146a1439SMasami Hiramatsu 	if (ret != 3) {
922146a1439SMasami Hiramatsu 		semantic_error("Failed to parse event name: %s\n", argv[0]);
923146a1439SMasami Hiramatsu 		ret = -EINVAL;
924146a1439SMasami Hiramatsu 		goto out;
925146a1439SMasami Hiramatsu 	}
9264235b045SMasami Hiramatsu 	pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr);
9274de189feSMasami Hiramatsu 
9284235b045SMasami Hiramatsu 	tp->retprobe = (pr == 'r');
9294de189feSMasami Hiramatsu 
9304de189feSMasami Hiramatsu 	/* Scan function name and offset */
9314235b045SMasami Hiramatsu 	ret = sscanf(argv[1], "%a[^+]+%lu", (float *)(void *)&tp->symbol,
9324235b045SMasami Hiramatsu 		     &tp->offset);
9334de189feSMasami Hiramatsu 	if (ret == 1)
9344235b045SMasami Hiramatsu 		tp->offset = 0;
9354de189feSMasami Hiramatsu 
9364235b045SMasami Hiramatsu 	tev->nargs = argc - 2;
9370e60836bSSrikar Dronamraju 	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
938e334016fSMasami Hiramatsu 	if (tev->args == NULL) {
939e334016fSMasami Hiramatsu 		ret = -ENOMEM;
940e334016fSMasami Hiramatsu 		goto out;
941e334016fSMasami Hiramatsu 	}
9424235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
9434de189feSMasami Hiramatsu 		p = strchr(argv[i + 2], '=');
9444de189feSMasami Hiramatsu 		if (p)	/* We don't need which register is assigned. */
9454235b045SMasami Hiramatsu 			*p++ = '\0';
9464235b045SMasami Hiramatsu 		else
9474235b045SMasami Hiramatsu 			p = argv[i + 2];
94802b95dadSMasami Hiramatsu 		tev->args[i].name = strdup(argv[i + 2]);
9494235b045SMasami Hiramatsu 		/* TODO: parse regs and offset */
95002b95dadSMasami Hiramatsu 		tev->args[i].value = strdup(p);
95102b95dadSMasami Hiramatsu 		if (tev->args[i].name == NULL || tev->args[i].value == NULL) {
95202b95dadSMasami Hiramatsu 			ret = -ENOMEM;
95302b95dadSMasami Hiramatsu 			goto out;
95402b95dadSMasami Hiramatsu 		}
9554de189feSMasami Hiramatsu 	}
956146a1439SMasami Hiramatsu 	ret = 0;
957146a1439SMasami Hiramatsu out:
9584de189feSMasami Hiramatsu 	argv_free(argv);
959146a1439SMasami Hiramatsu 	return ret;
9604de189feSMasami Hiramatsu }
9614de189feSMasami Hiramatsu 
9627df2f329SMasami Hiramatsu /* Compose only probe arg */
9637df2f329SMasami Hiramatsu int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
9647df2f329SMasami Hiramatsu {
9657df2f329SMasami Hiramatsu 	struct perf_probe_arg_field *field = pa->field;
9667df2f329SMasami Hiramatsu 	int ret;
9677df2f329SMasami Hiramatsu 	char *tmp = buf;
9687df2f329SMasami Hiramatsu 
96948481938SMasami Hiramatsu 	if (pa->name && pa->var)
97048481938SMasami Hiramatsu 		ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var);
97148481938SMasami Hiramatsu 	else
97248481938SMasami Hiramatsu 		ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var);
9737df2f329SMasami Hiramatsu 	if (ret <= 0)
9747df2f329SMasami Hiramatsu 		goto error;
9757df2f329SMasami Hiramatsu 	tmp += ret;
9767df2f329SMasami Hiramatsu 	len -= ret;
9777df2f329SMasami Hiramatsu 
9787df2f329SMasami Hiramatsu 	while (field) {
979b2a3c12bSMasami Hiramatsu 		if (field->name[0] == '[')
980b2a3c12bSMasami Hiramatsu 			ret = e_snprintf(tmp, len, "%s", field->name);
981b2a3c12bSMasami Hiramatsu 		else
982b2a3c12bSMasami Hiramatsu 			ret = e_snprintf(tmp, len, "%s%s",
983b2a3c12bSMasami Hiramatsu 					 field->ref ? "->" : ".", field->name);
9847df2f329SMasami Hiramatsu 		if (ret <= 0)
9857df2f329SMasami Hiramatsu 			goto error;
9867df2f329SMasami Hiramatsu 		tmp += ret;
9877df2f329SMasami Hiramatsu 		len -= ret;
9887df2f329SMasami Hiramatsu 		field = field->next;
9897df2f329SMasami Hiramatsu 	}
99011a1ca35SMasami Hiramatsu 
99111a1ca35SMasami Hiramatsu 	if (pa->type) {
99211a1ca35SMasami Hiramatsu 		ret = e_snprintf(tmp, len, ":%s", pa->type);
99311a1ca35SMasami Hiramatsu 		if (ret <= 0)
99411a1ca35SMasami Hiramatsu 			goto error;
99511a1ca35SMasami Hiramatsu 		tmp += ret;
99611a1ca35SMasami Hiramatsu 		len -= ret;
99711a1ca35SMasami Hiramatsu 	}
99811a1ca35SMasami Hiramatsu 
9997df2f329SMasami Hiramatsu 	return tmp - buf;
10007df2f329SMasami Hiramatsu error:
10010e43e5d2SMasami Hiramatsu 	pr_debug("Failed to synthesize perf probe argument: %s\n",
1002146a1439SMasami Hiramatsu 		 strerror(-ret));
1003146a1439SMasami Hiramatsu 	return ret;
10047df2f329SMasami Hiramatsu }
10057df2f329SMasami Hiramatsu 
10064235b045SMasami Hiramatsu /* Compose only probe point (not argument) */
10074235b045SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
100850656eecSMasami Hiramatsu {
1009fb1587d8SMasami Hiramatsu 	char *buf, *tmp;
1010fb1587d8SMasami Hiramatsu 	char offs[32] = "", line[32] = "", file[32] = "";
1011fb1587d8SMasami Hiramatsu 	int ret, len;
101250656eecSMasami Hiramatsu 
1013e334016fSMasami Hiramatsu 	buf = zalloc(MAX_CMDLEN);
1014e334016fSMasami Hiramatsu 	if (buf == NULL) {
1015e334016fSMasami Hiramatsu 		ret = -ENOMEM;
1016e334016fSMasami Hiramatsu 		goto error;
1017e334016fSMasami Hiramatsu 	}
10184de189feSMasami Hiramatsu 	if (pp->offset) {
1019fb1587d8SMasami Hiramatsu 		ret = e_snprintf(offs, 32, "+%lu", pp->offset);
10204de189feSMasami Hiramatsu 		if (ret <= 0)
10214de189feSMasami Hiramatsu 			goto error;
10224de189feSMasami Hiramatsu 	}
10234de189feSMasami Hiramatsu 	if (pp->line) {
1024fb1587d8SMasami Hiramatsu 		ret = e_snprintf(line, 32, ":%d", pp->line);
1025fb1587d8SMasami Hiramatsu 		if (ret <= 0)
1026fb1587d8SMasami Hiramatsu 			goto error;
1027fb1587d8SMasami Hiramatsu 	}
1028fb1587d8SMasami Hiramatsu 	if (pp->file) {
1029dd259c5dSMasami Hiramatsu 		len = strlen(pp->file) - 31;
1030fb1587d8SMasami Hiramatsu 		if (len < 0)
1031fb1587d8SMasami Hiramatsu 			len = 0;
1032fb1587d8SMasami Hiramatsu 		tmp = strchr(pp->file + len, '/');
1033fb1587d8SMasami Hiramatsu 		if (!tmp)
1034dd259c5dSMasami Hiramatsu 			tmp = pp->file + len;
1035fb1587d8SMasami Hiramatsu 		ret = e_snprintf(file, 32, "@%s", tmp + 1);
10364de189feSMasami Hiramatsu 		if (ret <= 0)
10374de189feSMasami Hiramatsu 			goto error;
10384de189feSMasami Hiramatsu 	}
10394de189feSMasami Hiramatsu 
10404de189feSMasami Hiramatsu 	if (pp->function)
1041fb1587d8SMasami Hiramatsu 		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function,
1042fb1587d8SMasami Hiramatsu 				 offs, pp->retprobe ? "%return" : "", line,
1043fb1587d8SMasami Hiramatsu 				 file);
10444de189feSMasami Hiramatsu 	else
1045fb1587d8SMasami Hiramatsu 		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line);
10464235b045SMasami Hiramatsu 	if (ret <= 0)
10474235b045SMasami Hiramatsu 		goto error;
10484235b045SMasami Hiramatsu 
10494235b045SMasami Hiramatsu 	return buf;
10504235b045SMasami Hiramatsu error:
10510e43e5d2SMasami Hiramatsu 	pr_debug("Failed to synthesize perf probe point: %s\n",
1052146a1439SMasami Hiramatsu 		 strerror(-ret));
1053e334016fSMasami Hiramatsu 	if (buf)
1054146a1439SMasami Hiramatsu 		free(buf);
1055146a1439SMasami Hiramatsu 	return NULL;
10564235b045SMasami Hiramatsu }
10574235b045SMasami Hiramatsu 
10584235b045SMasami Hiramatsu #if 0
10594235b045SMasami Hiramatsu char *synthesize_perf_probe_command(struct perf_probe_event *pev)
10604235b045SMasami Hiramatsu {
10614235b045SMasami Hiramatsu 	char *buf;
10624235b045SMasami Hiramatsu 	int i, len, ret;
10634235b045SMasami Hiramatsu 
10644235b045SMasami Hiramatsu 	buf = synthesize_perf_probe_point(&pev->point);
10654235b045SMasami Hiramatsu 	if (!buf)
10664235b045SMasami Hiramatsu 		return NULL;
10674235b045SMasami Hiramatsu 
10684235b045SMasami Hiramatsu 	len = strlen(buf);
10694235b045SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++) {
10704235b045SMasami Hiramatsu 		ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
10714235b045SMasami Hiramatsu 				 pev->args[i].name);
10727ef17aafSMasami Hiramatsu 		if (ret <= 0) {
10734235b045SMasami Hiramatsu 			free(buf);
10744235b045SMasami Hiramatsu 			return NULL;
10757ef17aafSMasami Hiramatsu 		}
10764235b045SMasami Hiramatsu 		len += ret;
10777ef17aafSMasami Hiramatsu 	}
107850656eecSMasami Hiramatsu 
10794235b045SMasami Hiramatsu 	return buf;
10804235b045SMasami Hiramatsu }
10814235b045SMasami Hiramatsu #endif
10824235b045SMasami Hiramatsu 
10830e60836bSSrikar Dronamraju static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
10844235b045SMasami Hiramatsu 					     char **buf, size_t *buflen,
10854235b045SMasami Hiramatsu 					     int depth)
10867ef17aafSMasami Hiramatsu {
10874235b045SMasami Hiramatsu 	int ret;
10884235b045SMasami Hiramatsu 	if (ref->next) {
10890e60836bSSrikar Dronamraju 		depth = __synthesize_probe_trace_arg_ref(ref->next, buf,
10904235b045SMasami Hiramatsu 							 buflen, depth + 1);
10914235b045SMasami Hiramatsu 		if (depth < 0)
10924235b045SMasami Hiramatsu 			goto out;
10934235b045SMasami Hiramatsu 	}
10944235b045SMasami Hiramatsu 
10954235b045SMasami Hiramatsu 	ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset);
10964235b045SMasami Hiramatsu 	if (ret < 0)
10974235b045SMasami Hiramatsu 		depth = ret;
10984235b045SMasami Hiramatsu 	else {
10994235b045SMasami Hiramatsu 		*buf += ret;
11004235b045SMasami Hiramatsu 		*buflen -= ret;
11014235b045SMasami Hiramatsu 	}
11024235b045SMasami Hiramatsu out:
11034235b045SMasami Hiramatsu 	return depth;
11044235b045SMasami Hiramatsu 
11054235b045SMasami Hiramatsu }
11064235b045SMasami Hiramatsu 
11070e60836bSSrikar Dronamraju static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
11084235b045SMasami Hiramatsu 				       char *buf, size_t buflen)
11094235b045SMasami Hiramatsu {
11100e60836bSSrikar Dronamraju 	struct probe_trace_arg_ref *ref = arg->ref;
11114235b045SMasami Hiramatsu 	int ret, depth = 0;
11124235b045SMasami Hiramatsu 	char *tmp = buf;
11134235b045SMasami Hiramatsu 
11144235b045SMasami Hiramatsu 	/* Argument name or separator */
11154235b045SMasami Hiramatsu 	if (arg->name)
11164235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, " %s=", arg->name);
11174235b045SMasami Hiramatsu 	else
11184235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, " ");
11194235b045SMasami Hiramatsu 	if (ret < 0)
11204235b045SMasami Hiramatsu 		return ret;
11214235b045SMasami Hiramatsu 	buf += ret;
11224235b045SMasami Hiramatsu 	buflen -= ret;
11234235b045SMasami Hiramatsu 
1124b7dcb857SMasami Hiramatsu 	/* Special case: @XXX */
1125b7dcb857SMasami Hiramatsu 	if (arg->value[0] == '@' && arg->ref)
1126b7dcb857SMasami Hiramatsu 			ref = ref->next;
1127b7dcb857SMasami Hiramatsu 
11284235b045SMasami Hiramatsu 	/* Dereferencing arguments */
1129b7dcb857SMasami Hiramatsu 	if (ref) {
11300e60836bSSrikar Dronamraju 		depth = __synthesize_probe_trace_arg_ref(ref, &buf,
11314235b045SMasami Hiramatsu 							  &buflen, 1);
11324235b045SMasami Hiramatsu 		if (depth < 0)
11334235b045SMasami Hiramatsu 			return depth;
11344235b045SMasami Hiramatsu 	}
11354235b045SMasami Hiramatsu 
11364235b045SMasami Hiramatsu 	/* Print argument value */
1137b7dcb857SMasami Hiramatsu 	if (arg->value[0] == '@' && arg->ref)
1138b7dcb857SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, "%s%+ld", arg->value,
1139b7dcb857SMasami Hiramatsu 				 arg->ref->offset);
1140b7dcb857SMasami Hiramatsu 	else
11414235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, "%s", arg->value);
11424235b045SMasami Hiramatsu 	if (ret < 0)
11434235b045SMasami Hiramatsu 		return ret;
11444235b045SMasami Hiramatsu 	buf += ret;
11454235b045SMasami Hiramatsu 	buflen -= ret;
11464235b045SMasami Hiramatsu 
11474235b045SMasami Hiramatsu 	/* Closing */
11484235b045SMasami Hiramatsu 	while (depth--) {
11494235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, ")");
11504235b045SMasami Hiramatsu 		if (ret < 0)
11514235b045SMasami Hiramatsu 			return ret;
11524235b045SMasami Hiramatsu 		buf += ret;
11534235b045SMasami Hiramatsu 		buflen -= ret;
11544235b045SMasami Hiramatsu 	}
11554984912eSMasami Hiramatsu 	/* Print argument type */
11564984912eSMasami Hiramatsu 	if (arg->type) {
11574984912eSMasami Hiramatsu 		ret = e_snprintf(buf, buflen, ":%s", arg->type);
11584984912eSMasami Hiramatsu 		if (ret <= 0)
11594984912eSMasami Hiramatsu 			return ret;
11604984912eSMasami Hiramatsu 		buf += ret;
11614984912eSMasami Hiramatsu 	}
11624235b045SMasami Hiramatsu 
11634235b045SMasami Hiramatsu 	return buf - tmp;
11644235b045SMasami Hiramatsu }
11654235b045SMasami Hiramatsu 
11660e60836bSSrikar Dronamraju char *synthesize_probe_trace_command(struct probe_trace_event *tev)
11674235b045SMasami Hiramatsu {
11680e60836bSSrikar Dronamraju 	struct probe_trace_point *tp = &tev->point;
11697ef17aafSMasami Hiramatsu 	char *buf;
11707ef17aafSMasami Hiramatsu 	int i, len, ret;
11717ef17aafSMasami Hiramatsu 
1172e334016fSMasami Hiramatsu 	buf = zalloc(MAX_CMDLEN);
1173e334016fSMasami Hiramatsu 	if (buf == NULL)
1174e334016fSMasami Hiramatsu 		return NULL;
1175e334016fSMasami Hiramatsu 
11764235b045SMasami Hiramatsu 	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu",
11774235b045SMasami Hiramatsu 			 tp->retprobe ? 'r' : 'p',
11784235b045SMasami Hiramatsu 			 tev->group, tev->event,
11794235b045SMasami Hiramatsu 			 tp->symbol, tp->offset);
11804235b045SMasami Hiramatsu 	if (len <= 0)
11814235b045SMasami Hiramatsu 		goto error;
11827ef17aafSMasami Hiramatsu 
11834235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
11840e60836bSSrikar Dronamraju 		ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
11854235b045SMasami Hiramatsu 						  MAX_CMDLEN - len);
11864de189feSMasami Hiramatsu 		if (ret <= 0)
118750656eecSMasami Hiramatsu 			goto error;
118850656eecSMasami Hiramatsu 		len += ret;
118950656eecSMasami Hiramatsu 	}
119050656eecSMasami Hiramatsu 
11914235b045SMasami Hiramatsu 	return buf;
119250656eecSMasami Hiramatsu error:
11934235b045SMasami Hiramatsu 	free(buf);
11944235b045SMasami Hiramatsu 	return NULL;
119550656eecSMasami Hiramatsu }
119650656eecSMasami Hiramatsu 
11970e60836bSSrikar Dronamraju static int convert_to_perf_probe_event(struct probe_trace_event *tev,
11984235b045SMasami Hiramatsu 				       struct perf_probe_event *pev)
11994de189feSMasami Hiramatsu {
120002b95dadSMasami Hiramatsu 	char buf[64] = "";
1201146a1439SMasami Hiramatsu 	int i, ret;
12024de189feSMasami Hiramatsu 
12034b4da7f7SMasami Hiramatsu 	/* Convert event/group name */
120402b95dadSMasami Hiramatsu 	pev->event = strdup(tev->event);
120502b95dadSMasami Hiramatsu 	pev->group = strdup(tev->group);
120602b95dadSMasami Hiramatsu 	if (pev->event == NULL || pev->group == NULL)
120702b95dadSMasami Hiramatsu 		return -ENOMEM;
1208fb1587d8SMasami Hiramatsu 
12094b4da7f7SMasami Hiramatsu 	/* Convert trace_point to probe_point */
12100e60836bSSrikar Dronamraju 	ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
1211146a1439SMasami Hiramatsu 	if (ret < 0)
1212146a1439SMasami Hiramatsu 		return ret;
12134b4da7f7SMasami Hiramatsu 
12144235b045SMasami Hiramatsu 	/* Convert trace_arg to probe_arg */
12154235b045SMasami Hiramatsu 	pev->nargs = tev->nargs;
1216e334016fSMasami Hiramatsu 	pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
1217e334016fSMasami Hiramatsu 	if (pev->args == NULL)
1218e334016fSMasami Hiramatsu 		return -ENOMEM;
121902b95dadSMasami Hiramatsu 	for (i = 0; i < tev->nargs && ret >= 0; i++) {
12204235b045SMasami Hiramatsu 		if (tev->args[i].name)
122102b95dadSMasami Hiramatsu 			pev->args[i].name = strdup(tev->args[i].name);
12224235b045SMasami Hiramatsu 		else {
12230e60836bSSrikar Dronamraju 			ret = synthesize_probe_trace_arg(&tev->args[i],
1224146a1439SMasami Hiramatsu 							  buf, 64);
122502b95dadSMasami Hiramatsu 			pev->args[i].name = strdup(buf);
122602b95dadSMasami Hiramatsu 		}
122702b95dadSMasami Hiramatsu 		if (pev->args[i].name == NULL && ret >= 0)
122802b95dadSMasami Hiramatsu 			ret = -ENOMEM;
12294de189feSMasami Hiramatsu 	}
1230146a1439SMasami Hiramatsu 
1231146a1439SMasami Hiramatsu 	if (ret < 0)
1232146a1439SMasami Hiramatsu 		clear_perf_probe_event(pev);
1233146a1439SMasami Hiramatsu 
1234146a1439SMasami Hiramatsu 	return ret;
12354235b045SMasami Hiramatsu }
12364de189feSMasami Hiramatsu 
12374235b045SMasami Hiramatsu void clear_perf_probe_event(struct perf_probe_event *pev)
12384235b045SMasami Hiramatsu {
12394235b045SMasami Hiramatsu 	struct perf_probe_point *pp = &pev->point;
12407df2f329SMasami Hiramatsu 	struct perf_probe_arg_field *field, *next;
12414235b045SMasami Hiramatsu 	int i;
12424de189feSMasami Hiramatsu 
12434235b045SMasami Hiramatsu 	if (pev->event)
12444235b045SMasami Hiramatsu 		free(pev->event);
12454235b045SMasami Hiramatsu 	if (pev->group)
12464235b045SMasami Hiramatsu 		free(pev->group);
12474235b045SMasami Hiramatsu 	if (pp->file)
12484235b045SMasami Hiramatsu 		free(pp->file);
12494235b045SMasami Hiramatsu 	if (pp->function)
12504235b045SMasami Hiramatsu 		free(pp->function);
12514235b045SMasami Hiramatsu 	if (pp->lazy_line)
12524235b045SMasami Hiramatsu 		free(pp->lazy_line);
12537df2f329SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++) {
12544235b045SMasami Hiramatsu 		if (pev->args[i].name)
12554235b045SMasami Hiramatsu 			free(pev->args[i].name);
125648481938SMasami Hiramatsu 		if (pev->args[i].var)
125748481938SMasami Hiramatsu 			free(pev->args[i].var);
125811a1ca35SMasami Hiramatsu 		if (pev->args[i].type)
125911a1ca35SMasami Hiramatsu 			free(pev->args[i].type);
12607df2f329SMasami Hiramatsu 		field = pev->args[i].field;
12617df2f329SMasami Hiramatsu 		while (field) {
12627df2f329SMasami Hiramatsu 			next = field->next;
12637df2f329SMasami Hiramatsu 			if (field->name)
12647df2f329SMasami Hiramatsu 				free(field->name);
12657df2f329SMasami Hiramatsu 			free(field);
12667df2f329SMasami Hiramatsu 			field = next;
12677df2f329SMasami Hiramatsu 		}
12687df2f329SMasami Hiramatsu 	}
12694235b045SMasami Hiramatsu 	if (pev->args)
12704235b045SMasami Hiramatsu 		free(pev->args);
12714235b045SMasami Hiramatsu 	memset(pev, 0, sizeof(*pev));
12724235b045SMasami Hiramatsu }
12734235b045SMasami Hiramatsu 
12740e60836bSSrikar Dronamraju static void clear_probe_trace_event(struct probe_trace_event *tev)
12754235b045SMasami Hiramatsu {
12760e60836bSSrikar Dronamraju 	struct probe_trace_arg_ref *ref, *next;
12774235b045SMasami Hiramatsu 	int i;
12784235b045SMasami Hiramatsu 
12794235b045SMasami Hiramatsu 	if (tev->event)
12804235b045SMasami Hiramatsu 		free(tev->event);
12814235b045SMasami Hiramatsu 	if (tev->group)
12824235b045SMasami Hiramatsu 		free(tev->group);
12834235b045SMasami Hiramatsu 	if (tev->point.symbol)
12844235b045SMasami Hiramatsu 		free(tev->point.symbol);
12854235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
12864235b045SMasami Hiramatsu 		if (tev->args[i].name)
12874235b045SMasami Hiramatsu 			free(tev->args[i].name);
12884235b045SMasami Hiramatsu 		if (tev->args[i].value)
12894235b045SMasami Hiramatsu 			free(tev->args[i].value);
12904984912eSMasami Hiramatsu 		if (tev->args[i].type)
12914984912eSMasami Hiramatsu 			free(tev->args[i].type);
12924235b045SMasami Hiramatsu 		ref = tev->args[i].ref;
12934235b045SMasami Hiramatsu 		while (ref) {
12944235b045SMasami Hiramatsu 			next = ref->next;
12954235b045SMasami Hiramatsu 			free(ref);
12964235b045SMasami Hiramatsu 			ref = next;
12974235b045SMasami Hiramatsu 		}
12984235b045SMasami Hiramatsu 	}
12994235b045SMasami Hiramatsu 	if (tev->args)
13004235b045SMasami Hiramatsu 		free(tev->args);
13014235b045SMasami Hiramatsu 	memset(tev, 0, sizeof(*tev));
13024de189feSMasami Hiramatsu }
13034de189feSMasami Hiramatsu 
1304f4d7da49SMasami Hiramatsu static int open_kprobe_events(bool readwrite)
13054de189feSMasami Hiramatsu {
13064de189feSMasami Hiramatsu 	char buf[PATH_MAX];
13077ca5989dSMasami Hiramatsu 	const char *__debugfs;
13084de189feSMasami Hiramatsu 	int ret;
13094de189feSMasami Hiramatsu 
13107ca5989dSMasami Hiramatsu 	__debugfs = debugfs_find_mountpoint();
13117ca5989dSMasami Hiramatsu 	if (__debugfs == NULL) {
13127ca5989dSMasami Hiramatsu 		pr_warning("Debugfs is not mounted.\n");
13137ca5989dSMasami Hiramatsu 		return -ENOENT;
13147ca5989dSMasami Hiramatsu 	}
13157ca5989dSMasami Hiramatsu 
13167ca5989dSMasami Hiramatsu 	ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs);
1317146a1439SMasami Hiramatsu 	if (ret >= 0) {
13187ca5989dSMasami Hiramatsu 		pr_debug("Opening %s write=%d\n", buf, readwrite);
1319f4d7da49SMasami Hiramatsu 		if (readwrite && !probe_event_dry_run)
1320f4d7da49SMasami Hiramatsu 			ret = open(buf, O_RDWR, O_APPEND);
1321f4d7da49SMasami Hiramatsu 		else
1322f4d7da49SMasami Hiramatsu 			ret = open(buf, O_RDONLY, 0);
1323146a1439SMasami Hiramatsu 	}
1324f4d7da49SMasami Hiramatsu 
13254de189feSMasami Hiramatsu 	if (ret < 0) {
13264de189feSMasami Hiramatsu 		if (errno == ENOENT)
1327146a1439SMasami Hiramatsu 			pr_warning("kprobe_events file does not exist - please"
1328146a1439SMasami Hiramatsu 				 " rebuild kernel with CONFIG_KPROBE_EVENT.\n");
13294de189feSMasami Hiramatsu 		else
1330146a1439SMasami Hiramatsu 			pr_warning("Failed to open kprobe_events file: %s\n",
13314de189feSMasami Hiramatsu 				   strerror(errno));
13324de189feSMasami Hiramatsu 	}
13334de189feSMasami Hiramatsu 	return ret;
13344de189feSMasami Hiramatsu }
13354de189feSMasami Hiramatsu 
13364de189feSMasami Hiramatsu /* Get raw string list of current kprobe_events */
13370e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_command_rawlist(int fd)
13384de189feSMasami Hiramatsu {
13394de189feSMasami Hiramatsu 	int ret, idx;
13404de189feSMasami Hiramatsu 	FILE *fp;
13414de189feSMasami Hiramatsu 	char buf[MAX_CMDLEN];
13424de189feSMasami Hiramatsu 	char *p;
13434de189feSMasami Hiramatsu 	struct strlist *sl;
13444de189feSMasami Hiramatsu 
13454de189feSMasami Hiramatsu 	sl = strlist__new(true, NULL);
13464de189feSMasami Hiramatsu 
13474de189feSMasami Hiramatsu 	fp = fdopen(dup(fd), "r");
13484de189feSMasami Hiramatsu 	while (!feof(fp)) {
13494de189feSMasami Hiramatsu 		p = fgets(buf, MAX_CMDLEN, fp);
13504de189feSMasami Hiramatsu 		if (!p)
13514de189feSMasami Hiramatsu 			break;
13524de189feSMasami Hiramatsu 
13534de189feSMasami Hiramatsu 		idx = strlen(p) - 1;
13544de189feSMasami Hiramatsu 		if (p[idx] == '\n')
13554de189feSMasami Hiramatsu 			p[idx] = '\0';
13564de189feSMasami Hiramatsu 		ret = strlist__add(sl, buf);
1357146a1439SMasami Hiramatsu 		if (ret < 0) {
1358146a1439SMasami Hiramatsu 			pr_debug("strlist__add failed: %s\n", strerror(-ret));
1359146a1439SMasami Hiramatsu 			strlist__delete(sl);
1360146a1439SMasami Hiramatsu 			return NULL;
1361146a1439SMasami Hiramatsu 		}
13624de189feSMasami Hiramatsu 	}
13634de189feSMasami Hiramatsu 	fclose(fp);
13644de189feSMasami Hiramatsu 
13654de189feSMasami Hiramatsu 	return sl;
13664de189feSMasami Hiramatsu }
13674de189feSMasami Hiramatsu 
1368278498d4SMasami Hiramatsu /* Show an event */
1369146a1439SMasami Hiramatsu static int show_perf_probe_event(struct perf_probe_event *pev)
1370278498d4SMasami Hiramatsu {
13717e990a51SMasami Hiramatsu 	int i, ret;
1372278498d4SMasami Hiramatsu 	char buf[128];
13734235b045SMasami Hiramatsu 	char *place;
1374278498d4SMasami Hiramatsu 
13754235b045SMasami Hiramatsu 	/* Synthesize only event probe point */
13764235b045SMasami Hiramatsu 	place = synthesize_perf_probe_point(&pev->point);
1377146a1439SMasami Hiramatsu 	if (!place)
1378146a1439SMasami Hiramatsu 		return -EINVAL;
13794235b045SMasami Hiramatsu 
13804235b045SMasami Hiramatsu 	ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event);
13817e990a51SMasami Hiramatsu 	if (ret < 0)
1382146a1439SMasami Hiramatsu 		return ret;
1383146a1439SMasami Hiramatsu 
1384fb1587d8SMasami Hiramatsu 	printf("  %-20s (on %s", buf, place);
1385278498d4SMasami Hiramatsu 
13864235b045SMasami Hiramatsu 	if (pev->nargs > 0) {
1387278498d4SMasami Hiramatsu 		printf(" with");
13887df2f329SMasami Hiramatsu 		for (i = 0; i < pev->nargs; i++) {
1389146a1439SMasami Hiramatsu 			ret = synthesize_perf_probe_arg(&pev->args[i],
1390146a1439SMasami Hiramatsu 							buf, 128);
1391146a1439SMasami Hiramatsu 			if (ret < 0)
1392146a1439SMasami Hiramatsu 				break;
13937df2f329SMasami Hiramatsu 			printf(" %s", buf);
13947df2f329SMasami Hiramatsu 		}
1395278498d4SMasami Hiramatsu 	}
1396278498d4SMasami Hiramatsu 	printf(")\n");
13974235b045SMasami Hiramatsu 	free(place);
1398146a1439SMasami Hiramatsu 	return ret;
1399278498d4SMasami Hiramatsu }
1400278498d4SMasami Hiramatsu 
14014de189feSMasami Hiramatsu /* List up current perf-probe events */
1402146a1439SMasami Hiramatsu int show_perf_probe_events(void)
14034de189feSMasami Hiramatsu {
1404146a1439SMasami Hiramatsu 	int fd, ret;
14050e60836bSSrikar Dronamraju 	struct probe_trace_event tev;
14064235b045SMasami Hiramatsu 	struct perf_probe_event pev;
14074de189feSMasami Hiramatsu 	struct strlist *rawlist;
14084de189feSMasami Hiramatsu 	struct str_node *ent;
14094de189feSMasami Hiramatsu 
141072041334SMasami Hiramatsu 	setup_pager();
1411146a1439SMasami Hiramatsu 	ret = init_vmlinux();
1412146a1439SMasami Hiramatsu 	if (ret < 0)
1413146a1439SMasami Hiramatsu 		return ret;
14144235b045SMasami Hiramatsu 
14154235b045SMasami Hiramatsu 	memset(&tev, 0, sizeof(tev));
14164235b045SMasami Hiramatsu 	memset(&pev, 0, sizeof(pev));
141772041334SMasami Hiramatsu 
1418f4d7da49SMasami Hiramatsu 	fd = open_kprobe_events(false);
1419146a1439SMasami Hiramatsu 	if (fd < 0)
1420146a1439SMasami Hiramatsu 		return fd;
1421146a1439SMasami Hiramatsu 
14220e60836bSSrikar Dronamraju 	rawlist = get_probe_trace_command_rawlist(fd);
14234de189feSMasami Hiramatsu 	close(fd);
1424146a1439SMasami Hiramatsu 	if (!rawlist)
1425146a1439SMasami Hiramatsu 		return -ENOENT;
14264de189feSMasami Hiramatsu 
1427adf365f4SMasami Hiramatsu 	strlist__for_each(ent, rawlist) {
14280e60836bSSrikar Dronamraju 		ret = parse_probe_trace_command(ent->s, &tev);
1429146a1439SMasami Hiramatsu 		if (ret >= 0) {
1430146a1439SMasami Hiramatsu 			ret = convert_to_perf_probe_event(&tev, &pev);
1431146a1439SMasami Hiramatsu 			if (ret >= 0)
1432146a1439SMasami Hiramatsu 				ret = show_perf_probe_event(&pev);
1433146a1439SMasami Hiramatsu 		}
14344235b045SMasami Hiramatsu 		clear_perf_probe_event(&pev);
14350e60836bSSrikar Dronamraju 		clear_probe_trace_event(&tev);
1436146a1439SMasami Hiramatsu 		if (ret < 0)
1437146a1439SMasami Hiramatsu 			break;
14384de189feSMasami Hiramatsu 	}
14394de189feSMasami Hiramatsu 	strlist__delete(rawlist);
1440146a1439SMasami Hiramatsu 
1441146a1439SMasami Hiramatsu 	return ret;
14424de189feSMasami Hiramatsu }
14434de189feSMasami Hiramatsu 
1444b498ce1fSMasami Hiramatsu /* Get current perf-probe event names */
14450e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
1446b498ce1fSMasami Hiramatsu {
1447fa28244dSMasami Hiramatsu 	char buf[128];
1448b498ce1fSMasami Hiramatsu 	struct strlist *sl, *rawlist;
1449b498ce1fSMasami Hiramatsu 	struct str_node *ent;
14500e60836bSSrikar Dronamraju 	struct probe_trace_event tev;
1451146a1439SMasami Hiramatsu 	int ret = 0;
1452b498ce1fSMasami Hiramatsu 
14534235b045SMasami Hiramatsu 	memset(&tev, 0, sizeof(tev));
14540e60836bSSrikar Dronamraju 	rawlist = get_probe_trace_command_rawlist(fd);
1455e1d2017bSMasami Hiramatsu 	sl = strlist__new(true, NULL);
1456adf365f4SMasami Hiramatsu 	strlist__for_each(ent, rawlist) {
14570e60836bSSrikar Dronamraju 		ret = parse_probe_trace_command(ent->s, &tev);
1458146a1439SMasami Hiramatsu 		if (ret < 0)
1459146a1439SMasami Hiramatsu 			break;
1460fa28244dSMasami Hiramatsu 		if (include_group) {
1461146a1439SMasami Hiramatsu 			ret = e_snprintf(buf, 128, "%s:%s", tev.group,
1462146a1439SMasami Hiramatsu 					tev.event);
1463146a1439SMasami Hiramatsu 			if (ret >= 0)
1464146a1439SMasami Hiramatsu 				ret = strlist__add(sl, buf);
1465fa28244dSMasami Hiramatsu 		} else
1466146a1439SMasami Hiramatsu 			ret = strlist__add(sl, tev.event);
14670e60836bSSrikar Dronamraju 		clear_probe_trace_event(&tev);
1468146a1439SMasami Hiramatsu 		if (ret < 0)
1469146a1439SMasami Hiramatsu 			break;
1470b498ce1fSMasami Hiramatsu 	}
1471b498ce1fSMasami Hiramatsu 	strlist__delete(rawlist);
1472b498ce1fSMasami Hiramatsu 
1473146a1439SMasami Hiramatsu 	if (ret < 0) {
1474146a1439SMasami Hiramatsu 		strlist__delete(sl);
1475146a1439SMasami Hiramatsu 		return NULL;
1476146a1439SMasami Hiramatsu 	}
1477b498ce1fSMasami Hiramatsu 	return sl;
1478b498ce1fSMasami Hiramatsu }
1479b498ce1fSMasami Hiramatsu 
14800e60836bSSrikar Dronamraju static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
148150656eecSMasami Hiramatsu {
14826eca8cc3SFrederic Weisbecker 	int ret = 0;
14830e60836bSSrikar Dronamraju 	char *buf = synthesize_probe_trace_command(tev);
148450656eecSMasami Hiramatsu 
1485146a1439SMasami Hiramatsu 	if (!buf) {
14860e60836bSSrikar Dronamraju 		pr_debug("Failed to synthesize probe trace event.\n");
1487146a1439SMasami Hiramatsu 		return -EINVAL;
1488146a1439SMasami Hiramatsu 	}
1489146a1439SMasami Hiramatsu 
1490fa28244dSMasami Hiramatsu 	pr_debug("Writing event: %s\n", buf);
1491f4d7da49SMasami Hiramatsu 	if (!probe_event_dry_run) {
149250656eecSMasami Hiramatsu 		ret = write(fd, buf, strlen(buf));
149350656eecSMasami Hiramatsu 		if (ret <= 0)
1494146a1439SMasami Hiramatsu 			pr_warning("Failed to write event: %s\n",
1495146a1439SMasami Hiramatsu 				   strerror(errno));
149650656eecSMasami Hiramatsu 	}
14974235b045SMasami Hiramatsu 	free(buf);
1498146a1439SMasami Hiramatsu 	return ret;
1499f4d7da49SMasami Hiramatsu }
150050656eecSMasami Hiramatsu 
1501146a1439SMasami Hiramatsu static int get_new_event_name(char *buf, size_t len, const char *base,
1502d761b08bSMasami Hiramatsu 			      struct strlist *namelist, bool allow_suffix)
1503b498ce1fSMasami Hiramatsu {
1504b498ce1fSMasami Hiramatsu 	int i, ret;
150517f88fcdSMasami Hiramatsu 
150617f88fcdSMasami Hiramatsu 	/* Try no suffix */
150717f88fcdSMasami Hiramatsu 	ret = e_snprintf(buf, len, "%s", base);
1508146a1439SMasami Hiramatsu 	if (ret < 0) {
1509146a1439SMasami Hiramatsu 		pr_debug("snprintf() failed: %s\n", strerror(-ret));
1510146a1439SMasami Hiramatsu 		return ret;
1511146a1439SMasami Hiramatsu 	}
151217f88fcdSMasami Hiramatsu 	if (!strlist__has_entry(namelist, buf))
1513146a1439SMasami Hiramatsu 		return 0;
151417f88fcdSMasami Hiramatsu 
1515d761b08bSMasami Hiramatsu 	if (!allow_suffix) {
1516d761b08bSMasami Hiramatsu 		pr_warning("Error: event \"%s\" already exists. "
1517d761b08bSMasami Hiramatsu 			   "(Use -f to force duplicates.)\n", base);
1518146a1439SMasami Hiramatsu 		return -EEXIST;
1519d761b08bSMasami Hiramatsu 	}
1520d761b08bSMasami Hiramatsu 
152117f88fcdSMasami Hiramatsu 	/* Try to add suffix */
152217f88fcdSMasami Hiramatsu 	for (i = 1; i < MAX_EVENT_INDEX; i++) {
1523b498ce1fSMasami Hiramatsu 		ret = e_snprintf(buf, len, "%s_%d", base, i);
1524146a1439SMasami Hiramatsu 		if (ret < 0) {
1525146a1439SMasami Hiramatsu 			pr_debug("snprintf() failed: %s\n", strerror(-ret));
1526146a1439SMasami Hiramatsu 			return ret;
1527146a1439SMasami Hiramatsu 		}
1528b498ce1fSMasami Hiramatsu 		if (!strlist__has_entry(namelist, buf))
1529b498ce1fSMasami Hiramatsu 			break;
1530b498ce1fSMasami Hiramatsu 	}
1531146a1439SMasami Hiramatsu 	if (i == MAX_EVENT_INDEX) {
1532146a1439SMasami Hiramatsu 		pr_warning("Too many events are on the same function.\n");
1533146a1439SMasami Hiramatsu 		ret = -ERANGE;
1534b498ce1fSMasami Hiramatsu 	}
1535b498ce1fSMasami Hiramatsu 
1536146a1439SMasami Hiramatsu 	return ret;
1537146a1439SMasami Hiramatsu }
1538146a1439SMasami Hiramatsu 
15390e60836bSSrikar Dronamraju static int __add_probe_trace_events(struct perf_probe_event *pev,
15400e60836bSSrikar Dronamraju 				     struct probe_trace_event *tevs,
15414235b045SMasami Hiramatsu 				     int ntevs, bool allow_suffix)
154250656eecSMasami Hiramatsu {
1543146a1439SMasami Hiramatsu 	int i, fd, ret;
15440e60836bSSrikar Dronamraju 	struct probe_trace_event *tev = NULL;
15454235b045SMasami Hiramatsu 	char buf[64];
15464235b045SMasami Hiramatsu 	const char *event, *group;
1547b498ce1fSMasami Hiramatsu 	struct strlist *namelist;
154850656eecSMasami Hiramatsu 
1549f4d7da49SMasami Hiramatsu 	fd = open_kprobe_events(true);
1550146a1439SMasami Hiramatsu 	if (fd < 0)
1551146a1439SMasami Hiramatsu 		return fd;
1552b498ce1fSMasami Hiramatsu 	/* Get current event names */
15530e60836bSSrikar Dronamraju 	namelist = get_probe_trace_event_names(fd, false);
1554146a1439SMasami Hiramatsu 	if (!namelist) {
1555146a1439SMasami Hiramatsu 		pr_debug("Failed to get current event list.\n");
1556146a1439SMasami Hiramatsu 		return -EIO;
1557146a1439SMasami Hiramatsu 	}
155850656eecSMasami Hiramatsu 
1559146a1439SMasami Hiramatsu 	ret = 0;
15604235b045SMasami Hiramatsu 	printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":");
156102b95dadSMasami Hiramatsu 	for (i = 0; i < ntevs; i++) {
15624235b045SMasami Hiramatsu 		tev = &tevs[i];
15634235b045SMasami Hiramatsu 		if (pev->event)
15644235b045SMasami Hiramatsu 			event = pev->event;
15654235b045SMasami Hiramatsu 		else
15664235b045SMasami Hiramatsu 			if (pev->point.function)
15674235b045SMasami Hiramatsu 				event = pev->point.function;
15684235b045SMasami Hiramatsu 			else
15694235b045SMasami Hiramatsu 				event = tev->point.symbol;
15704235b045SMasami Hiramatsu 		if (pev->group)
15714235b045SMasami Hiramatsu 			group = pev->group;
15724235b045SMasami Hiramatsu 		else
15734235b045SMasami Hiramatsu 			group = PERFPROBE_GROUP;
15744235b045SMasami Hiramatsu 
1575b498ce1fSMasami Hiramatsu 		/* Get an unused new event name */
1576146a1439SMasami Hiramatsu 		ret = get_new_event_name(buf, 64, event,
1577146a1439SMasami Hiramatsu 					 namelist, allow_suffix);
1578146a1439SMasami Hiramatsu 		if (ret < 0)
1579146a1439SMasami Hiramatsu 			break;
15804235b045SMasami Hiramatsu 		event = buf;
15814235b045SMasami Hiramatsu 
158202b95dadSMasami Hiramatsu 		tev->event = strdup(event);
158302b95dadSMasami Hiramatsu 		tev->group = strdup(group);
158402b95dadSMasami Hiramatsu 		if (tev->event == NULL || tev->group == NULL) {
158502b95dadSMasami Hiramatsu 			ret = -ENOMEM;
158602b95dadSMasami Hiramatsu 			break;
158702b95dadSMasami Hiramatsu 		}
15880e60836bSSrikar Dronamraju 		ret = write_probe_trace_event(fd, tev);
1589146a1439SMasami Hiramatsu 		if (ret < 0)
1590146a1439SMasami Hiramatsu 			break;
1591b498ce1fSMasami Hiramatsu 		/* Add added event name to namelist */
1592b498ce1fSMasami Hiramatsu 		strlist__add(namelist, event);
15934235b045SMasami Hiramatsu 
15944235b045SMasami Hiramatsu 		/* Trick here - save current event/group */
15954235b045SMasami Hiramatsu 		event = pev->event;
15964235b045SMasami Hiramatsu 		group = pev->group;
15974235b045SMasami Hiramatsu 		pev->event = tev->event;
15984235b045SMasami Hiramatsu 		pev->group = tev->group;
15994235b045SMasami Hiramatsu 		show_perf_probe_event(pev);
16004235b045SMasami Hiramatsu 		/* Trick here - restore current event/group */
16014235b045SMasami Hiramatsu 		pev->event = (char *)event;
16024235b045SMasami Hiramatsu 		pev->group = (char *)group;
16034235b045SMasami Hiramatsu 
1604d761b08bSMasami Hiramatsu 		/*
1605d761b08bSMasami Hiramatsu 		 * Probes after the first probe which comes from same
1606d761b08bSMasami Hiramatsu 		 * user input are always allowed to add suffix, because
1607d761b08bSMasami Hiramatsu 		 * there might be several addresses corresponding to
1608d761b08bSMasami Hiramatsu 		 * one code line.
1609d761b08bSMasami Hiramatsu 		 */
1610d761b08bSMasami Hiramatsu 		allow_suffix = true;
161150656eecSMasami Hiramatsu 	}
1612146a1439SMasami Hiramatsu 
1613146a1439SMasami Hiramatsu 	if (ret >= 0) {
1614a9b495b0SMasami Hiramatsu 		/* Show how to use the event. */
1615a9b495b0SMasami Hiramatsu 		printf("\nYou can now use it on all perf tools, such as:\n\n");
1616146a1439SMasami Hiramatsu 		printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
1617146a1439SMasami Hiramatsu 			 tev->event);
1618146a1439SMasami Hiramatsu 	}
1619a9b495b0SMasami Hiramatsu 
1620e1d2017bSMasami Hiramatsu 	strlist__delete(namelist);
162150656eecSMasami Hiramatsu 	close(fd);
1622146a1439SMasami Hiramatsu 	return ret;
162350656eecSMasami Hiramatsu }
1624fa28244dSMasami Hiramatsu 
16250e60836bSSrikar Dronamraju static int convert_to_probe_trace_events(struct perf_probe_event *pev,
16260e60836bSSrikar Dronamraju 					  struct probe_trace_event **tevs,
1627469b9b88SMasami Hiramatsu 					  int max_tevs, const char *module)
1628e0faa8d3SMasami Hiramatsu {
1629e0faa8d3SMasami Hiramatsu 	struct symbol *sym;
1630e334016fSMasami Hiramatsu 	int ret = 0, i;
16310e60836bSSrikar Dronamraju 	struct probe_trace_event *tev;
16324235b045SMasami Hiramatsu 
16334b4da7f7SMasami Hiramatsu 	/* Convert perf_probe_event with debuginfo */
1634469b9b88SMasami Hiramatsu 	ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);
1635e334016fSMasami Hiramatsu 	if (ret != 0)
1636e334016fSMasami Hiramatsu 		return ret;
1637e0faa8d3SMasami Hiramatsu 
16384235b045SMasami Hiramatsu 	/* Allocate trace event buffer */
16390e60836bSSrikar Dronamraju 	tev = *tevs = zalloc(sizeof(struct probe_trace_event));
1640e334016fSMasami Hiramatsu 	if (tev == NULL)
1641e334016fSMasami Hiramatsu 		return -ENOMEM;
1642e0faa8d3SMasami Hiramatsu 
16434235b045SMasami Hiramatsu 	/* Copy parameters */
164402b95dadSMasami Hiramatsu 	tev->point.symbol = strdup(pev->point.function);
164502b95dadSMasami Hiramatsu 	if (tev->point.symbol == NULL) {
164602b95dadSMasami Hiramatsu 		ret = -ENOMEM;
164702b95dadSMasami Hiramatsu 		goto error;
164802b95dadSMasami Hiramatsu 	}
16494235b045SMasami Hiramatsu 	tev->point.offset = pev->point.offset;
165004ddd04bSMasami Hiramatsu 	tev->point.retprobe = pev->point.retprobe;
16514235b045SMasami Hiramatsu 	tev->nargs = pev->nargs;
16524235b045SMasami Hiramatsu 	if (tev->nargs) {
16530e60836bSSrikar Dronamraju 		tev->args = zalloc(sizeof(struct probe_trace_arg)
16544235b045SMasami Hiramatsu 				   * tev->nargs);
1655e334016fSMasami Hiramatsu 		if (tev->args == NULL) {
165602b95dadSMasami Hiramatsu 			ret = -ENOMEM;
165702b95dadSMasami Hiramatsu 			goto error;
1658e334016fSMasami Hiramatsu 		}
165948481938SMasami Hiramatsu 		for (i = 0; i < tev->nargs; i++) {
166002b95dadSMasami Hiramatsu 			if (pev->args[i].name) {
166102b95dadSMasami Hiramatsu 				tev->args[i].name = strdup(pev->args[i].name);
166202b95dadSMasami Hiramatsu 				if (tev->args[i].name == NULL) {
166302b95dadSMasami Hiramatsu 					ret = -ENOMEM;
166402b95dadSMasami Hiramatsu 					goto error;
166502b95dadSMasami Hiramatsu 				}
166602b95dadSMasami Hiramatsu 			}
166702b95dadSMasami Hiramatsu 			tev->args[i].value = strdup(pev->args[i].var);
166802b95dadSMasami Hiramatsu 			if (tev->args[i].value == NULL) {
166902b95dadSMasami Hiramatsu 				ret = -ENOMEM;
167002b95dadSMasami Hiramatsu 				goto error;
167102b95dadSMasami Hiramatsu 			}
167202b95dadSMasami Hiramatsu 			if (pev->args[i].type) {
167302b95dadSMasami Hiramatsu 				tev->args[i].type = strdup(pev->args[i].type);
167402b95dadSMasami Hiramatsu 				if (tev->args[i].type == NULL) {
167502b95dadSMasami Hiramatsu 					ret = -ENOMEM;
167602b95dadSMasami Hiramatsu 					goto error;
167702b95dadSMasami Hiramatsu 				}
167802b95dadSMasami Hiramatsu 			}
167948481938SMasami Hiramatsu 		}
1680e0faa8d3SMasami Hiramatsu 	}
1681e0faa8d3SMasami Hiramatsu 
16824235b045SMasami Hiramatsu 	/* Currently just checking function name from symbol map */
1683469b9b88SMasami Hiramatsu 	sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
1684146a1439SMasami Hiramatsu 	if (!sym) {
1685146a1439SMasami Hiramatsu 		pr_warning("Kernel symbol \'%s\' not found.\n",
16864235b045SMasami Hiramatsu 			   tev->point.symbol);
168702b95dadSMasami Hiramatsu 		ret = -ENOENT;
168802b95dadSMasami Hiramatsu 		goto error;
168902b95dadSMasami Hiramatsu 	}
169002b95dadSMasami Hiramatsu 
169102b95dadSMasami Hiramatsu 	return 1;
169202b95dadSMasami Hiramatsu error:
16930e60836bSSrikar Dronamraju 	clear_probe_trace_event(tev);
1694e334016fSMasami Hiramatsu 	free(tev);
1695e334016fSMasami Hiramatsu 	*tevs = NULL;
1696e334016fSMasami Hiramatsu 	return ret;
16974235b045SMasami Hiramatsu }
16984235b045SMasami Hiramatsu 
16994235b045SMasami Hiramatsu struct __event_package {
17004235b045SMasami Hiramatsu 	struct perf_probe_event		*pev;
17010e60836bSSrikar Dronamraju 	struct probe_trace_event	*tevs;
17024235b045SMasami Hiramatsu 	int				ntevs;
17034235b045SMasami Hiramatsu };
17044235b045SMasami Hiramatsu 
1705146a1439SMasami Hiramatsu int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1706469b9b88SMasami Hiramatsu 			  int max_tevs, const char *module, bool force_add)
17074235b045SMasami Hiramatsu {
1708146a1439SMasami Hiramatsu 	int i, j, ret;
17094235b045SMasami Hiramatsu 	struct __event_package *pkgs;
17104235b045SMasami Hiramatsu 
1711e334016fSMasami Hiramatsu 	pkgs = zalloc(sizeof(struct __event_package) * npevs);
1712e334016fSMasami Hiramatsu 	if (pkgs == NULL)
1713e334016fSMasami Hiramatsu 		return -ENOMEM;
17144235b045SMasami Hiramatsu 
17154235b045SMasami Hiramatsu 	/* Init vmlinux path */
1716146a1439SMasami Hiramatsu 	ret = init_vmlinux();
1717449e5b24SMasami Hiramatsu 	if (ret < 0) {
1718449e5b24SMasami Hiramatsu 		free(pkgs);
1719146a1439SMasami Hiramatsu 		return ret;
1720449e5b24SMasami Hiramatsu 	}
17214235b045SMasami Hiramatsu 
17224235b045SMasami Hiramatsu 	/* Loop 1: convert all events */
17234235b045SMasami Hiramatsu 	for (i = 0; i < npevs; i++) {
17244235b045SMasami Hiramatsu 		pkgs[i].pev = &pevs[i];
17254235b045SMasami Hiramatsu 		/* Convert with or without debuginfo */
17260e60836bSSrikar Dronamraju 		ret  = convert_to_probe_trace_events(pkgs[i].pev,
1727469b9b88SMasami Hiramatsu 						     &pkgs[i].tevs,
1728469b9b88SMasami Hiramatsu 						     max_tevs,
1729469b9b88SMasami Hiramatsu 						     module);
1730146a1439SMasami Hiramatsu 		if (ret < 0)
1731146a1439SMasami Hiramatsu 			goto end;
1732146a1439SMasami Hiramatsu 		pkgs[i].ntevs = ret;
17334235b045SMasami Hiramatsu 	}
17344235b045SMasami Hiramatsu 
17354235b045SMasami Hiramatsu 	/* Loop 2: add all events */
1736146a1439SMasami Hiramatsu 	for (i = 0; i < npevs && ret >= 0; i++)
17370e60836bSSrikar Dronamraju 		ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs,
17384235b045SMasami Hiramatsu 						pkgs[i].ntevs, force_add);
1739146a1439SMasami Hiramatsu end:
1740449e5b24SMasami Hiramatsu 	/* Loop 3: cleanup and free trace events  */
1741449e5b24SMasami Hiramatsu 	for (i = 0; i < npevs; i++) {
1742146a1439SMasami Hiramatsu 		for (j = 0; j < pkgs[i].ntevs; j++)
17430e60836bSSrikar Dronamraju 			clear_probe_trace_event(&pkgs[i].tevs[j]);
1744449e5b24SMasami Hiramatsu 		free(pkgs[i].tevs);
1745449e5b24SMasami Hiramatsu 	}
1746449e5b24SMasami Hiramatsu 	free(pkgs);
1747146a1439SMasami Hiramatsu 
1748146a1439SMasami Hiramatsu 	return ret;
1749e0faa8d3SMasami Hiramatsu }
1750e0faa8d3SMasami Hiramatsu 
17510e60836bSSrikar Dronamraju static int __del_trace_probe_event(int fd, struct str_node *ent)
1752bbbb521bSMasami Hiramatsu {
1753bbbb521bSMasami Hiramatsu 	char *p;
1754bbbb521bSMasami Hiramatsu 	char buf[128];
17554235b045SMasami Hiramatsu 	int ret;
1756bbbb521bSMasami Hiramatsu 
17570e60836bSSrikar Dronamraju 	/* Convert from perf-probe event to trace-probe event */
1758146a1439SMasami Hiramatsu 	ret = e_snprintf(buf, 128, "-:%s", ent->s);
1759146a1439SMasami Hiramatsu 	if (ret < 0)
1760146a1439SMasami Hiramatsu 		goto error;
1761146a1439SMasami Hiramatsu 
1762bbbb521bSMasami Hiramatsu 	p = strchr(buf + 2, ':');
1763146a1439SMasami Hiramatsu 	if (!p) {
1764146a1439SMasami Hiramatsu 		pr_debug("Internal error: %s should have ':' but not.\n",
1765146a1439SMasami Hiramatsu 			 ent->s);
1766146a1439SMasami Hiramatsu 		ret = -ENOTSUP;
1767146a1439SMasami Hiramatsu 		goto error;
1768146a1439SMasami Hiramatsu 	}
1769bbbb521bSMasami Hiramatsu 	*p = '/';
1770bbbb521bSMasami Hiramatsu 
17714235b045SMasami Hiramatsu 	pr_debug("Writing event: %s\n", buf);
17724235b045SMasami Hiramatsu 	ret = write(fd, buf, strlen(buf));
1773146a1439SMasami Hiramatsu 	if (ret < 0)
1774146a1439SMasami Hiramatsu 		goto error;
1775146a1439SMasami Hiramatsu 
1776bbbb521bSMasami Hiramatsu 	printf("Remove event: %s\n", ent->s);
1777146a1439SMasami Hiramatsu 	return 0;
1778146a1439SMasami Hiramatsu error:
1779146a1439SMasami Hiramatsu 	pr_warning("Failed to delete event: %s\n", strerror(-ret));
1780146a1439SMasami Hiramatsu 	return ret;
1781bbbb521bSMasami Hiramatsu }
1782bbbb521bSMasami Hiramatsu 
17830e60836bSSrikar Dronamraju static int del_trace_probe_event(int fd, const char *group,
1784fa28244dSMasami Hiramatsu 				  const char *event, struct strlist *namelist)
1785fa28244dSMasami Hiramatsu {
1786fa28244dSMasami Hiramatsu 	char buf[128];
1787bbbb521bSMasami Hiramatsu 	struct str_node *ent, *n;
1788146a1439SMasami Hiramatsu 	int found = 0, ret = 0;
1789fa28244dSMasami Hiramatsu 
1790146a1439SMasami Hiramatsu 	ret = e_snprintf(buf, 128, "%s:%s", group, event);
1791146a1439SMasami Hiramatsu 	if (ret < 0) {
17920e43e5d2SMasami Hiramatsu 		pr_err("Failed to copy event.\n");
1793146a1439SMasami Hiramatsu 		return ret;
1794146a1439SMasami Hiramatsu 	}
1795fa28244dSMasami Hiramatsu 
1796bbbb521bSMasami Hiramatsu 	if (strpbrk(buf, "*?")) { /* Glob-exp */
1797bbbb521bSMasami Hiramatsu 		strlist__for_each_safe(ent, n, namelist)
1798bbbb521bSMasami Hiramatsu 			if (strglobmatch(ent->s, buf)) {
1799bbbb521bSMasami Hiramatsu 				found++;
18000e60836bSSrikar Dronamraju 				ret = __del_trace_probe_event(fd, ent);
1801146a1439SMasami Hiramatsu 				if (ret < 0)
1802146a1439SMasami Hiramatsu 					break;
18033e340590SMasami Hiramatsu 				strlist__remove(namelist, ent);
1804fa28244dSMasami Hiramatsu 			}
1805bbbb521bSMasami Hiramatsu 	} else {
1806bbbb521bSMasami Hiramatsu 		ent = strlist__find(namelist, buf);
1807bbbb521bSMasami Hiramatsu 		if (ent) {
1808bbbb521bSMasami Hiramatsu 			found++;
18090e60836bSSrikar Dronamraju 			ret = __del_trace_probe_event(fd, ent);
1810146a1439SMasami Hiramatsu 			if (ret >= 0)
1811bbbb521bSMasami Hiramatsu 				strlist__remove(namelist, ent);
1812bbbb521bSMasami Hiramatsu 		}
1813bbbb521bSMasami Hiramatsu 	}
1814146a1439SMasami Hiramatsu 	if (found == 0 && ret >= 0)
1815146a1439SMasami Hiramatsu 		pr_info("Info: Event \"%s\" does not exist.\n", buf);
1816146a1439SMasami Hiramatsu 
1817146a1439SMasami Hiramatsu 	return ret;
1818bbbb521bSMasami Hiramatsu }
1819fa28244dSMasami Hiramatsu 
1820146a1439SMasami Hiramatsu int del_perf_probe_events(struct strlist *dellist)
1821fa28244dSMasami Hiramatsu {
1822146a1439SMasami Hiramatsu 	int fd, ret = 0;
1823fa28244dSMasami Hiramatsu 	const char *group, *event;
1824fa28244dSMasami Hiramatsu 	char *p, *str;
1825fa28244dSMasami Hiramatsu 	struct str_node *ent;
1826fa28244dSMasami Hiramatsu 	struct strlist *namelist;
1827fa28244dSMasami Hiramatsu 
1828f4d7da49SMasami Hiramatsu 	fd = open_kprobe_events(true);
1829146a1439SMasami Hiramatsu 	if (fd < 0)
1830146a1439SMasami Hiramatsu 		return fd;
1831146a1439SMasami Hiramatsu 
1832fa28244dSMasami Hiramatsu 	/* Get current event names */
18330e60836bSSrikar Dronamraju 	namelist = get_probe_trace_event_names(fd, true);
1834146a1439SMasami Hiramatsu 	if (namelist == NULL)
1835146a1439SMasami Hiramatsu 		return -EINVAL;
1836fa28244dSMasami Hiramatsu 
1837adf365f4SMasami Hiramatsu 	strlist__for_each(ent, dellist) {
183802b95dadSMasami Hiramatsu 		str = strdup(ent->s);
183902b95dadSMasami Hiramatsu 		if (str == NULL) {
184002b95dadSMasami Hiramatsu 			ret = -ENOMEM;
184102b95dadSMasami Hiramatsu 			break;
184202b95dadSMasami Hiramatsu 		}
1843bbbb521bSMasami Hiramatsu 		pr_debug("Parsing: %s\n", str);
1844fa28244dSMasami Hiramatsu 		p = strchr(str, ':');
1845fa28244dSMasami Hiramatsu 		if (p) {
1846fa28244dSMasami Hiramatsu 			group = str;
1847fa28244dSMasami Hiramatsu 			*p = '\0';
1848fa28244dSMasami Hiramatsu 			event = p + 1;
1849fa28244dSMasami Hiramatsu 		} else {
1850bbbb521bSMasami Hiramatsu 			group = "*";
1851fa28244dSMasami Hiramatsu 			event = str;
1852fa28244dSMasami Hiramatsu 		}
1853bbbb521bSMasami Hiramatsu 		pr_debug("Group: %s, Event: %s\n", group, event);
18540e60836bSSrikar Dronamraju 		ret = del_trace_probe_event(fd, group, event, namelist);
1855fa28244dSMasami Hiramatsu 		free(str);
1856146a1439SMasami Hiramatsu 		if (ret < 0)
1857146a1439SMasami Hiramatsu 			break;
1858fa28244dSMasami Hiramatsu 	}
1859fa28244dSMasami Hiramatsu 	strlist__delete(namelist);
1860fa28244dSMasami Hiramatsu 	close(fd);
1861146a1439SMasami Hiramatsu 
1862146a1439SMasami Hiramatsu 	return ret;
1863fa28244dSMasami Hiramatsu }
1864fa28244dSMasami Hiramatsu 
1865