xref: /linux/tools/perf/util/probe-event.c (revision 1fb89448871500e5d5e7ad93d6dae68ee4fa464a)
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 #include <sys/utsname.h>
2350656eecSMasami Hiramatsu #include <sys/types.h>
2450656eecSMasami Hiramatsu #include <sys/stat.h>
2550656eecSMasami Hiramatsu #include <fcntl.h>
2650656eecSMasami Hiramatsu #include <errno.h>
2750656eecSMasami Hiramatsu #include <stdio.h>
2850656eecSMasami Hiramatsu #include <unistd.h>
2950656eecSMasami Hiramatsu #include <stdlib.h>
3050656eecSMasami Hiramatsu #include <string.h>
314de189feSMasami Hiramatsu #include <stdarg.h>
324de189feSMasami Hiramatsu #include <limits.h>
33e80711caSMasami Hiramatsu #include <elf.h>
3450656eecSMasami Hiramatsu 
3531facc5fSMasami Hiramatsu #include "util.h"
3650656eecSMasami Hiramatsu #include "event.h"
374de189feSMasami Hiramatsu #include "strlist.h"
3850656eecSMasami Hiramatsu #include "debug.h"
3972041334SMasami Hiramatsu #include "cache.h"
40631c9defSMasami Hiramatsu #include "color.h"
41e0faa8d3SMasami Hiramatsu #include "symbol.h"
42e0faa8d3SMasami Hiramatsu #include "thread.h"
437ca5989dSMasami Hiramatsu #include "debugfs.h"
444b4da7f7SMasami Hiramatsu #include "trace-event.h"	/* For __unused */
4550656eecSMasami Hiramatsu #include "probe-event.h"
464235b045SMasami Hiramatsu #include "probe-finder.h"
47225466f1SSrikar Dronamraju #include "session.h"
4850656eecSMasami Hiramatsu 
4950656eecSMasami Hiramatsu #define MAX_CMDLEN 256
5050656eecSMasami Hiramatsu #define MAX_PROBE_ARGS 128
5150656eecSMasami Hiramatsu #define PERFPROBE_GROUP "probe"
5250656eecSMasami Hiramatsu 
53f4d7da49SMasami Hiramatsu bool probe_event_dry_run;	/* Dry run flag */
54f4d7da49SMasami Hiramatsu 
55146a1439SMasami Hiramatsu #define semantic_error(msg ...) pr_err("Semantic error :" msg)
5650656eecSMasami Hiramatsu 
574de189feSMasami Hiramatsu /* If there is no space to write, returns -E2BIG. */
584de189feSMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...)
5984988450SMasami Hiramatsu 	__attribute__((format(printf, 3, 4)));
6084988450SMasami Hiramatsu 
6184988450SMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...)
624de189feSMasami Hiramatsu {
634de189feSMasami Hiramatsu 	int ret;
644de189feSMasami Hiramatsu 	va_list ap;
654de189feSMasami Hiramatsu 	va_start(ap, format);
664de189feSMasami Hiramatsu 	ret = vsnprintf(str, size, format, ap);
674de189feSMasami Hiramatsu 	va_end(ap);
684de189feSMasami Hiramatsu 	if (ret >= (int)size)
694de189feSMasami Hiramatsu 		ret = -E2BIG;
704de189feSMasami Hiramatsu 	return ret;
714de189feSMasami Hiramatsu }
724de189feSMasami Hiramatsu 
734b4da7f7SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
74225466f1SSrikar Dronamraju static int convert_name_to_addr(struct perf_probe_event *pev,
75225466f1SSrikar Dronamraju 				const char *exec);
76d28c6223SArnaldo Carvalho de Melo static struct machine machine;
77e0faa8d3SMasami Hiramatsu 
78469b9b88SMasami Hiramatsu /* Initialize symbol maps and path of vmlinux/modules */
79146a1439SMasami Hiramatsu static int init_vmlinux(void)
80e0faa8d3SMasami Hiramatsu {
81146a1439SMasami Hiramatsu 	int ret;
82146a1439SMasami Hiramatsu 
83e0faa8d3SMasami Hiramatsu 	symbol_conf.sort_by_name = true;
84e0faa8d3SMasami Hiramatsu 	if (symbol_conf.vmlinux_name == NULL)
85e0faa8d3SMasami Hiramatsu 		symbol_conf.try_vmlinux_path = true;
86e0faa8d3SMasami Hiramatsu 	else
87e0faa8d3SMasami Hiramatsu 		pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
88146a1439SMasami Hiramatsu 	ret = symbol__init();
89146a1439SMasami Hiramatsu 	if (ret < 0) {
90146a1439SMasami Hiramatsu 		pr_debug("Failed to init symbol map.\n");
91146a1439SMasami Hiramatsu 		goto out;
92146a1439SMasami Hiramatsu 	}
93e0faa8d3SMasami Hiramatsu 
94469b9b88SMasami Hiramatsu 	ret = machine__init(&machine, "", HOST_KERNEL_ID);
95d28c6223SArnaldo Carvalho de Melo 	if (ret < 0)
96d28c6223SArnaldo Carvalho de Melo 		goto out;
97d28c6223SArnaldo Carvalho de Melo 
98469b9b88SMasami Hiramatsu 	if (machine__create_kernel_maps(&machine) < 0) {
990e43e5d2SMasami Hiramatsu 		pr_debug("machine__create_kernel_maps() failed.\n");
100469b9b88SMasami Hiramatsu 		goto out;
101469b9b88SMasami Hiramatsu 	}
102146a1439SMasami Hiramatsu out:
103146a1439SMasami Hiramatsu 	if (ret < 0)
104146a1439SMasami Hiramatsu 		pr_warning("Failed to init vmlinux path.\n");
105146a1439SMasami Hiramatsu 	return ret;
106e0faa8d3SMasami Hiramatsu }
107e0faa8d3SMasami Hiramatsu 
108469b9b88SMasami Hiramatsu static struct symbol *__find_kernel_function_by_name(const char *name,
109469b9b88SMasami Hiramatsu 						     struct map **mapp)
110e0faa8d3SMasami Hiramatsu {
111469b9b88SMasami Hiramatsu 	return machine__find_kernel_function_by_name(&machine, name, mapp,
112469b9b88SMasami Hiramatsu 						     NULL);
113e0faa8d3SMasami Hiramatsu }
114469b9b88SMasami Hiramatsu 
115e80711caSMasami Hiramatsu static struct map *kernel_get_module_map(const char *module)
116e80711caSMasami Hiramatsu {
117e80711caSMasami Hiramatsu 	struct rb_node *nd;
118e80711caSMasami Hiramatsu 	struct map_groups *grp = &machine.kmaps;
119e80711caSMasami Hiramatsu 
12014a8fd7cSMasami Hiramatsu 	/* A file path -- this is an offline module */
12114a8fd7cSMasami Hiramatsu 	if (module && strchr(module, '/'))
12214a8fd7cSMasami Hiramatsu 		return machine__new_module(&machine, 0, module);
12314a8fd7cSMasami Hiramatsu 
124e80711caSMasami Hiramatsu 	if (!module)
125e80711caSMasami Hiramatsu 		module = "kernel";
126e80711caSMasami Hiramatsu 
127e80711caSMasami Hiramatsu 	for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
128e80711caSMasami Hiramatsu 		struct map *pos = rb_entry(nd, struct map, rb_node);
129e80711caSMasami Hiramatsu 		if (strncmp(pos->dso->short_name + 1, module,
130e80711caSMasami Hiramatsu 			    pos->dso->short_name_len - 2) == 0) {
131e80711caSMasami Hiramatsu 			return pos;
132e80711caSMasami Hiramatsu 		}
133e80711caSMasami Hiramatsu 	}
134e80711caSMasami Hiramatsu 	return NULL;
135e80711caSMasami Hiramatsu }
136e80711caSMasami Hiramatsu 
137e80711caSMasami Hiramatsu static struct dso *kernel_get_module_dso(const char *module)
138469b9b88SMasami Hiramatsu {
139469b9b88SMasami Hiramatsu 	struct dso *dso;
140fd930ff9SFranck Bui-Huu 	struct map *map;
141fd930ff9SFranck Bui-Huu 	const char *vmlinux_name;
142469b9b88SMasami Hiramatsu 
143469b9b88SMasami Hiramatsu 	if (module) {
144469b9b88SMasami Hiramatsu 		list_for_each_entry(dso, &machine.kernel_dsos, node) {
145469b9b88SMasami Hiramatsu 			if (strncmp(dso->short_name + 1, module,
146469b9b88SMasami Hiramatsu 				    dso->short_name_len - 2) == 0)
147469b9b88SMasami Hiramatsu 				goto found;
148469b9b88SMasami Hiramatsu 		}
149469b9b88SMasami Hiramatsu 		pr_debug("Failed to find module %s.\n", module);
150469b9b88SMasami Hiramatsu 		return NULL;
151fd930ff9SFranck Bui-Huu 	}
152fd930ff9SFranck Bui-Huu 
153fd930ff9SFranck Bui-Huu 	map = machine.vmlinux_maps[MAP__FUNCTION];
154fd930ff9SFranck Bui-Huu 	dso = map->dso;
155fd930ff9SFranck Bui-Huu 
156fd930ff9SFranck Bui-Huu 	vmlinux_name = symbol_conf.vmlinux_name;
157fd930ff9SFranck Bui-Huu 	if (vmlinux_name) {
158fd930ff9SFranck Bui-Huu 		if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0)
159fd930ff9SFranck Bui-Huu 			return NULL;
160469b9b88SMasami Hiramatsu 	} else {
161c3a34e06SFranck Bui-Huu 		if (dso__load_vmlinux_path(dso, map, NULL) <= 0) {
162469b9b88SMasami Hiramatsu 			pr_debug("Failed to load kernel map.\n");
163469b9b88SMasami Hiramatsu 			return NULL;
164469b9b88SMasami Hiramatsu 		}
165469b9b88SMasami Hiramatsu 	}
166469b9b88SMasami Hiramatsu found:
167e80711caSMasami Hiramatsu 	return dso;
168e80711caSMasami Hiramatsu }
169e80711caSMasami Hiramatsu 
170e80711caSMasami Hiramatsu const char *kernel_get_module_path(const char *module)
171e80711caSMasami Hiramatsu {
172e80711caSMasami Hiramatsu 	struct dso *dso = kernel_get_module_dso(module);
173e80711caSMasami Hiramatsu 	return (dso) ? dso->long_name : NULL;
174469b9b88SMasami Hiramatsu }
175469b9b88SMasami Hiramatsu 
176225466f1SSrikar Dronamraju static int init_user_exec(void)
177225466f1SSrikar Dronamraju {
178225466f1SSrikar Dronamraju 	int ret = 0;
179225466f1SSrikar Dronamraju 
180225466f1SSrikar Dronamraju 	symbol_conf.try_vmlinux_path = false;
181225466f1SSrikar Dronamraju 	symbol_conf.sort_by_name = true;
182225466f1SSrikar Dronamraju 	ret = symbol__init();
183225466f1SSrikar Dronamraju 
184225466f1SSrikar Dronamraju 	if (ret < 0)
185225466f1SSrikar Dronamraju 		pr_debug("Failed to init symbol map.\n");
186225466f1SSrikar Dronamraju 
187225466f1SSrikar Dronamraju 	return ret;
188225466f1SSrikar Dronamraju }
189225466f1SSrikar Dronamraju 
190225466f1SSrikar Dronamraju static int convert_to_perf_probe_point(struct probe_trace_point *tp,
191225466f1SSrikar Dronamraju 					struct perf_probe_point *pp)
192225466f1SSrikar Dronamraju {
193225466f1SSrikar Dronamraju 	pp->function = strdup(tp->symbol);
194225466f1SSrikar Dronamraju 
195225466f1SSrikar Dronamraju 	if (pp->function == NULL)
196225466f1SSrikar Dronamraju 		return -ENOMEM;
197225466f1SSrikar Dronamraju 
198225466f1SSrikar Dronamraju 	pp->offset = tp->offset;
199225466f1SSrikar Dronamraju 	pp->retprobe = tp->retprobe;
200225466f1SSrikar Dronamraju 
201225466f1SSrikar Dronamraju 	return 0;
202225466f1SSrikar Dronamraju }
203225466f1SSrikar Dronamraju 
204469b9b88SMasami Hiramatsu #ifdef DWARF_SUPPORT
205ff741783SMasami Hiramatsu /* Open new debuginfo of given module */
206ff741783SMasami Hiramatsu static struct debuginfo *open_debuginfo(const char *module)
207469b9b88SMasami Hiramatsu {
20814a8fd7cSMasami Hiramatsu 	const char *path;
20914a8fd7cSMasami Hiramatsu 
21014a8fd7cSMasami Hiramatsu 	/* A file path -- this is an offline module */
21114a8fd7cSMasami Hiramatsu 	if (module && strchr(module, '/'))
21214a8fd7cSMasami Hiramatsu 		path = module;
21314a8fd7cSMasami Hiramatsu 	else {
21414a8fd7cSMasami Hiramatsu 		path = kernel_get_module_path(module);
215ff741783SMasami Hiramatsu 
216469b9b88SMasami Hiramatsu 		if (!path) {
2170e43e5d2SMasami Hiramatsu 			pr_err("Failed to find path of %s module.\n",
2180e43e5d2SMasami Hiramatsu 			       module ?: "kernel");
219ff741783SMasami Hiramatsu 			return NULL;
220469b9b88SMasami Hiramatsu 		}
22114a8fd7cSMasami Hiramatsu 	}
222ff741783SMasami Hiramatsu 	return debuginfo__new(path);
223e0faa8d3SMasami Hiramatsu }
2244b4da7f7SMasami Hiramatsu 
2250e60836bSSrikar Dronamraju /*
2260e60836bSSrikar Dronamraju  * Convert trace point to probe point with debuginfo
2270e60836bSSrikar Dronamraju  * Currently only handles kprobes.
2280e60836bSSrikar Dronamraju  */
2290e60836bSSrikar Dronamraju static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
2304b4da7f7SMasami Hiramatsu 					struct perf_probe_point *pp)
2314b4da7f7SMasami Hiramatsu {
2324b4da7f7SMasami Hiramatsu 	struct symbol *sym;
233469b9b88SMasami Hiramatsu 	struct map *map;
234469b9b88SMasami Hiramatsu 	u64 addr;
235469b9b88SMasami Hiramatsu 	int ret = -ENOENT;
236ff741783SMasami Hiramatsu 	struct debuginfo *dinfo;
2374b4da7f7SMasami Hiramatsu 
238469b9b88SMasami Hiramatsu 	sym = __find_kernel_function_by_name(tp->symbol, &map);
2394b4da7f7SMasami Hiramatsu 	if (sym) {
240469b9b88SMasami Hiramatsu 		addr = map->unmap_ip(map, sym->start + tp->offset);
2419486aa38SArnaldo Carvalho de Melo 		pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol,
242469b9b88SMasami Hiramatsu 			 tp->offset, addr);
243ff741783SMasami Hiramatsu 
244ff741783SMasami Hiramatsu 		dinfo = debuginfo__new_online_kernel(addr);
245ff741783SMasami Hiramatsu 		if (dinfo) {
246ff741783SMasami Hiramatsu 			ret = debuginfo__find_probe_point(dinfo,
247ff741783SMasami Hiramatsu 						 (unsigned long)addr, pp);
248ff741783SMasami Hiramatsu 			debuginfo__delete(dinfo);
249ff741783SMasami Hiramatsu 		} else {
250ff741783SMasami Hiramatsu 			pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n",
251ff741783SMasami Hiramatsu 				 addr);
252ff741783SMasami Hiramatsu 			ret = -ENOENT;
253ff741783SMasami Hiramatsu 		}
254146a1439SMasami Hiramatsu 	}
2554b4da7f7SMasami Hiramatsu 	if (ret <= 0) {
256146a1439SMasami Hiramatsu 		pr_debug("Failed to find corresponding probes from "
257146a1439SMasami Hiramatsu 			 "debuginfo. Use kprobe event information.\n");
258225466f1SSrikar Dronamraju 		return convert_to_perf_probe_point(tp, pp);
2594b4da7f7SMasami Hiramatsu 	}
2604b4da7f7SMasami Hiramatsu 	pp->retprobe = tp->retprobe;
261146a1439SMasami Hiramatsu 
262146a1439SMasami Hiramatsu 	return 0;
2634b4da7f7SMasami Hiramatsu }
2644b4da7f7SMasami Hiramatsu 
265190b57fcSMasami Hiramatsu static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
266190b57fcSMasami Hiramatsu 					    int ntevs, const char *module)
267190b57fcSMasami Hiramatsu {
26814a8fd7cSMasami Hiramatsu 	int i, ret = 0;
26914a8fd7cSMasami Hiramatsu 	char *tmp;
27014a8fd7cSMasami Hiramatsu 
27114a8fd7cSMasami Hiramatsu 	if (!module)
27214a8fd7cSMasami Hiramatsu 		return 0;
27314a8fd7cSMasami Hiramatsu 
27414a8fd7cSMasami Hiramatsu 	tmp = strrchr(module, '/');
27514a8fd7cSMasami Hiramatsu 	if (tmp) {
27614a8fd7cSMasami Hiramatsu 		/* This is a module path -- get the module name */
27714a8fd7cSMasami Hiramatsu 		module = strdup(tmp + 1);
27814a8fd7cSMasami Hiramatsu 		if (!module)
27914a8fd7cSMasami Hiramatsu 			return -ENOMEM;
28014a8fd7cSMasami Hiramatsu 		tmp = strchr(module, '.');
28114a8fd7cSMasami Hiramatsu 		if (tmp)
28214a8fd7cSMasami Hiramatsu 			*tmp = '\0';
28314a8fd7cSMasami Hiramatsu 		tmp = (char *)module;	/* For free() */
28414a8fd7cSMasami Hiramatsu 	}
28514a8fd7cSMasami Hiramatsu 
286190b57fcSMasami Hiramatsu 	for (i = 0; i < ntevs; i++) {
287190b57fcSMasami Hiramatsu 		tevs[i].point.module = strdup(module);
28814a8fd7cSMasami Hiramatsu 		if (!tevs[i].point.module) {
28914a8fd7cSMasami Hiramatsu 			ret = -ENOMEM;
29014a8fd7cSMasami Hiramatsu 			break;
291190b57fcSMasami Hiramatsu 		}
29214a8fd7cSMasami Hiramatsu 	}
29314a8fd7cSMasami Hiramatsu 
29414a8fd7cSMasami Hiramatsu 	if (tmp)
29514a8fd7cSMasami Hiramatsu 		free(tmp);
29614a8fd7cSMasami Hiramatsu 
29714a8fd7cSMasami Hiramatsu 	return ret;
298190b57fcSMasami Hiramatsu }
299190b57fcSMasami Hiramatsu 
3004b4da7f7SMasami Hiramatsu /* Try to find perf_probe_event with debuginfo */
3010e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
3020e60836bSSrikar Dronamraju 					  struct probe_trace_event **tevs,
3034eced234SSrikar Dronamraju 					  int max_tevs, const char *target)
3044b4da7f7SMasami Hiramatsu {
3054b4da7f7SMasami Hiramatsu 	bool need_dwarf = perf_probe_event_need_dwarf(pev);
306225466f1SSrikar Dronamraju 	struct debuginfo *dinfo;
307190b57fcSMasami Hiramatsu 	int ntevs, ret = 0;
3084b4da7f7SMasami Hiramatsu 
309225466f1SSrikar Dronamraju 	if (pev->uprobes) {
310225466f1SSrikar Dronamraju 		if (need_dwarf) {
311225466f1SSrikar Dronamraju 			pr_warning("Debuginfo-analysis is not yet supported"
312225466f1SSrikar Dronamraju 					" with -x/--exec option.\n");
313225466f1SSrikar Dronamraju 			return -ENOSYS;
314225466f1SSrikar Dronamraju 		}
315225466f1SSrikar Dronamraju 		return convert_name_to_addr(pev, target);
316225466f1SSrikar Dronamraju 	}
317225466f1SSrikar Dronamraju 
318225466f1SSrikar Dronamraju 	dinfo = open_debuginfo(target);
319225466f1SSrikar Dronamraju 
320ff741783SMasami Hiramatsu 	if (!dinfo) {
321146a1439SMasami Hiramatsu 		if (need_dwarf) {
322146a1439SMasami Hiramatsu 			pr_warning("Failed to open debuginfo file.\n");
323ff741783SMasami Hiramatsu 			return -ENOENT;
324146a1439SMasami Hiramatsu 		}
325ff741783SMasami Hiramatsu 		pr_debug("Could not open debuginfo. Try to use symbols.\n");
3264b4da7f7SMasami Hiramatsu 		return 0;
3274b4da7f7SMasami Hiramatsu 	}
3284b4da7f7SMasami Hiramatsu 
329ff741783SMasami Hiramatsu 	/* Searching trace events corresponding to a probe event */
330ff741783SMasami Hiramatsu 	ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs);
331ff741783SMasami Hiramatsu 
332ff741783SMasami Hiramatsu 	debuginfo__delete(dinfo);
3334b4da7f7SMasami Hiramatsu 
334146a1439SMasami Hiramatsu 	if (ntevs > 0) {	/* Succeeded to find trace events */
3350e60836bSSrikar Dronamraju 		pr_debug("find %d probe_trace_events.\n", ntevs);
3364eced234SSrikar Dronamraju 		if (target)
337190b57fcSMasami Hiramatsu 			ret = add_module_to_probe_trace_events(*tevs, ntevs,
3384eced234SSrikar Dronamraju 							       target);
339190b57fcSMasami Hiramatsu 		return ret < 0 ? ret : ntevs;
340146a1439SMasami Hiramatsu 	}
3414b4da7f7SMasami Hiramatsu 
342146a1439SMasami Hiramatsu 	if (ntevs == 0)	{	/* No error but failed to find probe point. */
343146a1439SMasami Hiramatsu 		pr_warning("Probe point '%s' not found.\n",
3444b4da7f7SMasami Hiramatsu 			   synthesize_perf_probe_point(&pev->point));
345146a1439SMasami Hiramatsu 		return -ENOENT;
346146a1439SMasami Hiramatsu 	}
347146a1439SMasami Hiramatsu 	/* Error path : ntevs < 0 */
34815eca306SMasami Hiramatsu 	pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
34915eca306SMasami Hiramatsu 	if (ntevs == -EBADF) {
35015eca306SMasami Hiramatsu 		pr_warning("Warning: No dwarf info found in the vmlinux - "
35115eca306SMasami Hiramatsu 			"please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
35215eca306SMasami Hiramatsu 		if (!need_dwarf) {
3530e43e5d2SMasami Hiramatsu 			pr_debug("Trying to use symbols.\n");
3544b4da7f7SMasami Hiramatsu 			return 0;
3554b4da7f7SMasami Hiramatsu 		}
35615eca306SMasami Hiramatsu 	}
35715eca306SMasami Hiramatsu 	return ntevs;
35815eca306SMasami Hiramatsu }
3594b4da7f7SMasami Hiramatsu 
3607cf0b79eSMasami Hiramatsu /*
3617cf0b79eSMasami Hiramatsu  * Find a src file from a DWARF tag path. Prepend optional source path prefix
3627cf0b79eSMasami Hiramatsu  * and chop off leading directories that do not exist. Result is passed back as
3637cf0b79eSMasami Hiramatsu  * a newly allocated path on success.
3647cf0b79eSMasami Hiramatsu  * Return 0 if file was found and readable, -errno otherwise.
3657cf0b79eSMasami Hiramatsu  */
3666a330a3cSMasami Hiramatsu static int get_real_path(const char *raw_path, const char *comp_dir,
3676a330a3cSMasami Hiramatsu 			 char **new_path)
3687cf0b79eSMasami Hiramatsu {
3696a330a3cSMasami Hiramatsu 	const char *prefix = symbol_conf.source_prefix;
3706a330a3cSMasami Hiramatsu 
3716a330a3cSMasami Hiramatsu 	if (!prefix) {
3726a330a3cSMasami Hiramatsu 		if (raw_path[0] != '/' && comp_dir)
3736a330a3cSMasami Hiramatsu 			/* If not an absolute path, try to use comp_dir */
3746a330a3cSMasami Hiramatsu 			prefix = comp_dir;
3756a330a3cSMasami Hiramatsu 		else {
3767cf0b79eSMasami Hiramatsu 			if (access(raw_path, R_OK) == 0) {
3777cf0b79eSMasami Hiramatsu 				*new_path = strdup(raw_path);
3787cf0b79eSMasami Hiramatsu 				return 0;
3797cf0b79eSMasami Hiramatsu 			} else
3807cf0b79eSMasami Hiramatsu 				return -errno;
3817cf0b79eSMasami Hiramatsu 		}
3826a330a3cSMasami Hiramatsu 	}
3837cf0b79eSMasami Hiramatsu 
3846a330a3cSMasami Hiramatsu 	*new_path = malloc((strlen(prefix) + strlen(raw_path) + 2));
3857cf0b79eSMasami Hiramatsu 	if (!*new_path)
3867cf0b79eSMasami Hiramatsu 		return -ENOMEM;
3877cf0b79eSMasami Hiramatsu 
3887cf0b79eSMasami Hiramatsu 	for (;;) {
3896a330a3cSMasami Hiramatsu 		sprintf(*new_path, "%s/%s", prefix, raw_path);
3907cf0b79eSMasami Hiramatsu 
3917cf0b79eSMasami Hiramatsu 		if (access(*new_path, R_OK) == 0)
3927cf0b79eSMasami Hiramatsu 			return 0;
3937cf0b79eSMasami Hiramatsu 
3946a330a3cSMasami Hiramatsu 		if (!symbol_conf.source_prefix)
3956a330a3cSMasami Hiramatsu 			/* In case of searching comp_dir, don't retry */
3966a330a3cSMasami Hiramatsu 			return -errno;
3976a330a3cSMasami Hiramatsu 
3987cf0b79eSMasami Hiramatsu 		switch (errno) {
3997cf0b79eSMasami Hiramatsu 		case ENAMETOOLONG:
4007cf0b79eSMasami Hiramatsu 		case ENOENT:
4017cf0b79eSMasami Hiramatsu 		case EROFS:
4027cf0b79eSMasami Hiramatsu 		case EFAULT:
4037cf0b79eSMasami Hiramatsu 			raw_path = strchr(++raw_path, '/');
4047cf0b79eSMasami Hiramatsu 			if (!raw_path) {
4057cf0b79eSMasami Hiramatsu 				free(*new_path);
4067cf0b79eSMasami Hiramatsu 				*new_path = NULL;
4077cf0b79eSMasami Hiramatsu 				return -ENOENT;
4087cf0b79eSMasami Hiramatsu 			}
4097cf0b79eSMasami Hiramatsu 			continue;
4107cf0b79eSMasami Hiramatsu 
4117cf0b79eSMasami Hiramatsu 		default:
4127cf0b79eSMasami Hiramatsu 			free(*new_path);
4137cf0b79eSMasami Hiramatsu 			*new_path = NULL;
4147cf0b79eSMasami Hiramatsu 			return -errno;
4157cf0b79eSMasami Hiramatsu 		}
4167cf0b79eSMasami Hiramatsu 	}
4177cf0b79eSMasami Hiramatsu }
4187cf0b79eSMasami Hiramatsu 
4194b4da7f7SMasami Hiramatsu #define LINEBUF_SIZE 256
4204b4da7f7SMasami Hiramatsu #define NR_ADDITIONAL_LINES 2
4214b4da7f7SMasami Hiramatsu 
422fde52dbdSFranck Bui-Huu static int __show_one_line(FILE *fp, int l, bool skip, bool show_num)
4234b4da7f7SMasami Hiramatsu {
4244b4da7f7SMasami Hiramatsu 	char buf[LINEBUF_SIZE];
425befe3414SFranck Bui-Huu 	const char *color = show_num ? "" : PERF_COLOR_BLUE;
426befe3414SFranck Bui-Huu 	const char *prefix = NULL;
4274b4da7f7SMasami Hiramatsu 
428befe3414SFranck Bui-Huu 	do {
4294b4da7f7SMasami Hiramatsu 		if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
4304b4da7f7SMasami Hiramatsu 			goto error;
431befe3414SFranck Bui-Huu 		if (skip)
432befe3414SFranck Bui-Huu 			continue;
433befe3414SFranck Bui-Huu 		if (!prefix) {
434befe3414SFranck Bui-Huu 			prefix = show_num ? "%7d  " : "         ";
435befe3414SFranck Bui-Huu 			color_fprintf(stdout, color, prefix, l);
4364b4da7f7SMasami Hiramatsu 		}
437befe3414SFranck Bui-Huu 		color_fprintf(stdout, color, "%s", buf);
4384b4da7f7SMasami Hiramatsu 
439befe3414SFranck Bui-Huu 	} while (strchr(buf, '\n') == NULL);
440146a1439SMasami Hiramatsu 
441fde52dbdSFranck Bui-Huu 	return 1;
4424b4da7f7SMasami Hiramatsu error:
443fde52dbdSFranck Bui-Huu 	if (ferror(fp)) {
44432b2b6ecSFranck Bui-Huu 		pr_warning("File read error: %s\n", strerror(errno));
445146a1439SMasami Hiramatsu 		return -1;
4464b4da7f7SMasami Hiramatsu 	}
447fde52dbdSFranck Bui-Huu 	return 0;
448fde52dbdSFranck Bui-Huu }
449fde52dbdSFranck Bui-Huu 
450fde52dbdSFranck Bui-Huu static int _show_one_line(FILE *fp, int l, bool skip, bool show_num)
451fde52dbdSFranck Bui-Huu {
452fde52dbdSFranck Bui-Huu 	int rv = __show_one_line(fp, l, skip, show_num);
453fde52dbdSFranck Bui-Huu 	if (rv == 0) {
454fde52dbdSFranck Bui-Huu 		pr_warning("Source file is shorter than expected.\n");
455fde52dbdSFranck Bui-Huu 		rv = -1;
456fde52dbdSFranck Bui-Huu 	}
457fde52dbdSFranck Bui-Huu 	return rv;
458fde52dbdSFranck Bui-Huu }
459fde52dbdSFranck Bui-Huu 
460fde52dbdSFranck Bui-Huu #define show_one_line_with_num(f,l)	_show_one_line(f,l,false,true)
461fde52dbdSFranck Bui-Huu #define show_one_line(f,l)		_show_one_line(f,l,false,false)
462fde52dbdSFranck Bui-Huu #define skip_one_line(f,l)		_show_one_line(f,l,true,false)
463fde52dbdSFranck Bui-Huu #define show_one_line_or_eof(f,l)	__show_one_line(f,l,false,false)
4644b4da7f7SMasami Hiramatsu 
4654b4da7f7SMasami Hiramatsu /*
4664b4da7f7SMasami Hiramatsu  * Show line-range always requires debuginfo to find source file and
4674b4da7f7SMasami Hiramatsu  * line number.
4684b4da7f7SMasami Hiramatsu  */
469469b9b88SMasami Hiramatsu int show_line_range(struct line_range *lr, const char *module)
4704b4da7f7SMasami Hiramatsu {
471d3b63d7aSMasami Hiramatsu 	int l = 1;
4724b4da7f7SMasami Hiramatsu 	struct line_node *ln;
473ff741783SMasami Hiramatsu 	struct debuginfo *dinfo;
4744b4da7f7SMasami Hiramatsu 	FILE *fp;
475ff741783SMasami Hiramatsu 	int ret;
4767cf0b79eSMasami Hiramatsu 	char *tmp;
4774b4da7f7SMasami Hiramatsu 
4784b4da7f7SMasami Hiramatsu 	/* Search a line range */
479146a1439SMasami Hiramatsu 	ret = init_vmlinux();
480146a1439SMasami Hiramatsu 	if (ret < 0)
481146a1439SMasami Hiramatsu 		return ret;
482146a1439SMasami Hiramatsu 
483ff741783SMasami Hiramatsu 	dinfo = open_debuginfo(module);
484ff741783SMasami Hiramatsu 	if (!dinfo) {
485146a1439SMasami Hiramatsu 		pr_warning("Failed to open debuginfo file.\n");
486ff741783SMasami Hiramatsu 		return -ENOENT;
487146a1439SMasami Hiramatsu 	}
488146a1439SMasami Hiramatsu 
489ff741783SMasami Hiramatsu 	ret = debuginfo__find_line_range(dinfo, lr);
490ff741783SMasami Hiramatsu 	debuginfo__delete(dinfo);
491146a1439SMasami Hiramatsu 	if (ret == 0) {
492146a1439SMasami Hiramatsu 		pr_warning("Specified source line is not found.\n");
493146a1439SMasami Hiramatsu 		return -ENOENT;
494146a1439SMasami Hiramatsu 	} else if (ret < 0) {
495146a1439SMasami Hiramatsu 		pr_warning("Debuginfo analysis failed. (%d)\n", ret);
496146a1439SMasami Hiramatsu 		return ret;
497146a1439SMasami Hiramatsu 	}
4984b4da7f7SMasami Hiramatsu 
4997cf0b79eSMasami Hiramatsu 	/* Convert source file path */
5007cf0b79eSMasami Hiramatsu 	tmp = lr->path;
5016a330a3cSMasami Hiramatsu 	ret = get_real_path(tmp, lr->comp_dir, &lr->path);
5027cf0b79eSMasami Hiramatsu 	free(tmp);	/* Free old path */
5037cf0b79eSMasami Hiramatsu 	if (ret < 0) {
5047cf0b79eSMasami Hiramatsu 		pr_warning("Failed to find source file. (%d)\n", ret);
5057cf0b79eSMasami Hiramatsu 		return ret;
5067cf0b79eSMasami Hiramatsu 	}
5077cf0b79eSMasami Hiramatsu 
5084b4da7f7SMasami Hiramatsu 	setup_pager();
5094b4da7f7SMasami Hiramatsu 
5104b4da7f7SMasami Hiramatsu 	if (lr->function)
5118737ebdeSMasami Hiramatsu 		fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path,
5124b4da7f7SMasami Hiramatsu 			lr->start - lr->offset);
5134b4da7f7SMasami Hiramatsu 	else
51462c15fc4SFranck Bui-Huu 		fprintf(stdout, "<%s:%d>\n", lr->path, lr->start);
5154b4da7f7SMasami Hiramatsu 
5164b4da7f7SMasami Hiramatsu 	fp = fopen(lr->path, "r");
517146a1439SMasami Hiramatsu 	if (fp == NULL) {
518146a1439SMasami Hiramatsu 		pr_warning("Failed to open %s: %s\n", lr->path,
519146a1439SMasami Hiramatsu 			   strerror(errno));
520146a1439SMasami Hiramatsu 		return -errno;
521146a1439SMasami Hiramatsu 	}
5224b4da7f7SMasami Hiramatsu 	/* Skip to starting line number */
52344b81e92SFranck Bui-Huu 	while (l < lr->start) {
524fde52dbdSFranck Bui-Huu 		ret = skip_one_line(fp, l++);
525146a1439SMasami Hiramatsu 		if (ret < 0)
526146a1439SMasami Hiramatsu 			goto end;
52744b81e92SFranck Bui-Huu 	}
5284b4da7f7SMasami Hiramatsu 
5294b4da7f7SMasami Hiramatsu 	list_for_each_entry(ln, &lr->line_list, list) {
53044b81e92SFranck Bui-Huu 		for (; ln->line > l; l++) {
531fde52dbdSFranck Bui-Huu 			ret = show_one_line(fp, l - lr->offset);
53244b81e92SFranck Bui-Huu 			if (ret < 0)
53344b81e92SFranck Bui-Huu 				goto end;
53444b81e92SFranck Bui-Huu 		}
535fde52dbdSFranck Bui-Huu 		ret = show_one_line_with_num(fp, l++ - lr->offset);
536146a1439SMasami Hiramatsu 		if (ret < 0)
537146a1439SMasami Hiramatsu 			goto end;
5384b4da7f7SMasami Hiramatsu 	}
5394b4da7f7SMasami Hiramatsu 
5404b4da7f7SMasami Hiramatsu 	if (lr->end == INT_MAX)
5414b4da7f7SMasami Hiramatsu 		lr->end = l + NR_ADDITIONAL_LINES;
542fde52dbdSFranck Bui-Huu 	while (l <= lr->end) {
543fde52dbdSFranck Bui-Huu 		ret = show_one_line_or_eof(fp, l++ - lr->offset);
544fde52dbdSFranck Bui-Huu 		if (ret <= 0)
54544b81e92SFranck Bui-Huu 			break;
54644b81e92SFranck Bui-Huu 	}
547146a1439SMasami Hiramatsu end:
5484b4da7f7SMasami Hiramatsu 	fclose(fp);
549146a1439SMasami Hiramatsu 	return ret;
5504b4da7f7SMasami Hiramatsu }
5514b4da7f7SMasami Hiramatsu 
552ff741783SMasami Hiramatsu static int show_available_vars_at(struct debuginfo *dinfo,
553ff741783SMasami Hiramatsu 				  struct perf_probe_event *pev,
554bd09d7b5SMasami Hiramatsu 				  int max_vls, struct strfilter *_filter,
555bd09d7b5SMasami Hiramatsu 				  bool externs)
556cf6eb489SMasami Hiramatsu {
557cf6eb489SMasami Hiramatsu 	char *buf;
558bd09d7b5SMasami Hiramatsu 	int ret, i, nvars;
559cf6eb489SMasami Hiramatsu 	struct str_node *node;
560cf6eb489SMasami Hiramatsu 	struct variable_list *vls = NULL, *vl;
561bd09d7b5SMasami Hiramatsu 	const char *var;
562cf6eb489SMasami Hiramatsu 
563cf6eb489SMasami Hiramatsu 	buf = synthesize_perf_probe_point(&pev->point);
564cf6eb489SMasami Hiramatsu 	if (!buf)
565cf6eb489SMasami Hiramatsu 		return -EINVAL;
566cf6eb489SMasami Hiramatsu 	pr_debug("Searching variables at %s\n", buf);
567cf6eb489SMasami Hiramatsu 
568ff741783SMasami Hiramatsu 	ret = debuginfo__find_available_vars_at(dinfo, pev, &vls,
569ff741783SMasami Hiramatsu 						max_vls, externs);
570bd09d7b5SMasami Hiramatsu 	if (ret <= 0) {
571bd09d7b5SMasami Hiramatsu 		pr_err("Failed to find variables at %s (%d)\n", buf, ret);
572bd09d7b5SMasami Hiramatsu 		goto end;
573bd09d7b5SMasami Hiramatsu 	}
574bd09d7b5SMasami Hiramatsu 	/* Some variables are found */
575cf6eb489SMasami Hiramatsu 	fprintf(stdout, "Available variables at %s\n", buf);
576cf6eb489SMasami Hiramatsu 	for (i = 0; i < ret; i++) {
577cf6eb489SMasami Hiramatsu 		vl = &vls[i];
578cf6eb489SMasami Hiramatsu 		/*
579cf6eb489SMasami Hiramatsu 		 * A probe point might be converted to
580cf6eb489SMasami Hiramatsu 		 * several trace points.
581cf6eb489SMasami Hiramatsu 		 */
582cf6eb489SMasami Hiramatsu 		fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
583cf6eb489SMasami Hiramatsu 			vl->point.offset);
584cf6eb489SMasami Hiramatsu 		free(vl->point.symbol);
585bd09d7b5SMasami Hiramatsu 		nvars = 0;
586cf6eb489SMasami Hiramatsu 		if (vl->vars) {
587bd09d7b5SMasami Hiramatsu 			strlist__for_each(node, vl->vars) {
588bd09d7b5SMasami Hiramatsu 				var = strchr(node->s, '\t') + 1;
589bd09d7b5SMasami Hiramatsu 				if (strfilter__compare(_filter, var)) {
590cf6eb489SMasami Hiramatsu 					fprintf(stdout, "\t\t%s\n", node->s);
591bd09d7b5SMasami Hiramatsu 					nvars++;
592bd09d7b5SMasami Hiramatsu 				}
593bd09d7b5SMasami Hiramatsu 			}
594cf6eb489SMasami Hiramatsu 			strlist__delete(vl->vars);
595bd09d7b5SMasami Hiramatsu 		}
596bd09d7b5SMasami Hiramatsu 		if (nvars == 0)
597bd09d7b5SMasami Hiramatsu 			fprintf(stdout, "\t\t(No matched variables)\n");
598cf6eb489SMasami Hiramatsu 	}
599cf6eb489SMasami Hiramatsu 	free(vls);
600bd09d7b5SMasami Hiramatsu end:
601cf6eb489SMasami Hiramatsu 	free(buf);
602cf6eb489SMasami Hiramatsu 	return ret;
603cf6eb489SMasami Hiramatsu }
604cf6eb489SMasami Hiramatsu 
605cf6eb489SMasami Hiramatsu /* Show available variables on given probe point */
606cf6eb489SMasami Hiramatsu int show_available_vars(struct perf_probe_event *pevs, int npevs,
607bd09d7b5SMasami Hiramatsu 			int max_vls, const char *module,
608bd09d7b5SMasami Hiramatsu 			struct strfilter *_filter, bool externs)
609cf6eb489SMasami Hiramatsu {
610ff741783SMasami Hiramatsu 	int i, ret = 0;
611ff741783SMasami Hiramatsu 	struct debuginfo *dinfo;
612cf6eb489SMasami Hiramatsu 
613cf6eb489SMasami Hiramatsu 	ret = init_vmlinux();
614cf6eb489SMasami Hiramatsu 	if (ret < 0)
615cf6eb489SMasami Hiramatsu 		return ret;
616cf6eb489SMasami Hiramatsu 
617ff741783SMasami Hiramatsu 	dinfo = open_debuginfo(module);
618ff741783SMasami Hiramatsu 	if (!dinfo) {
619ff741783SMasami Hiramatsu 		pr_warning("Failed to open debuginfo file.\n");
620ff741783SMasami Hiramatsu 		return -ENOENT;
621ff741783SMasami Hiramatsu 	}
622ff741783SMasami Hiramatsu 
623cc446446SMasami Hiramatsu 	setup_pager();
624cc446446SMasami Hiramatsu 
625ff741783SMasami Hiramatsu 	for (i = 0; i < npevs && ret >= 0; i++)
626ff741783SMasami Hiramatsu 		ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter,
627bd09d7b5SMasami Hiramatsu 					     externs);
628ff741783SMasami Hiramatsu 
629ff741783SMasami Hiramatsu 	debuginfo__delete(dinfo);
630cf6eb489SMasami Hiramatsu 	return ret;
631cf6eb489SMasami Hiramatsu }
632cf6eb489SMasami Hiramatsu 
6334b4da7f7SMasami Hiramatsu #else	/* !DWARF_SUPPORT */
6344b4da7f7SMasami Hiramatsu 
6350e60836bSSrikar Dronamraju static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
6364b4da7f7SMasami Hiramatsu 					struct perf_probe_point *pp)
6374b4da7f7SMasami Hiramatsu {
638469b9b88SMasami Hiramatsu 	struct symbol *sym;
639469b9b88SMasami Hiramatsu 
640469b9b88SMasami Hiramatsu 	sym = __find_kernel_function_by_name(tp->symbol, NULL);
641469b9b88SMasami Hiramatsu 	if (!sym) {
642469b9b88SMasami Hiramatsu 		pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
643469b9b88SMasami Hiramatsu 		return -ENOENT;
644469b9b88SMasami Hiramatsu 	}
645146a1439SMasami Hiramatsu 
646225466f1SSrikar Dronamraju 	return convert_to_perf_probe_point(tp, pp);
6474b4da7f7SMasami Hiramatsu }
6484b4da7f7SMasami Hiramatsu 
6490e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
6500e60836bSSrikar Dronamraju 				struct probe_trace_event **tevs __unused,
651225466f1SSrikar Dronamraju 				int max_tevs __unused, const char *target)
6524b4da7f7SMasami Hiramatsu {
653146a1439SMasami Hiramatsu 	if (perf_probe_event_need_dwarf(pev)) {
654146a1439SMasami Hiramatsu 		pr_warning("Debuginfo-analysis is not supported.\n");
655146a1439SMasami Hiramatsu 		return -ENOSYS;
656146a1439SMasami Hiramatsu 	}
657225466f1SSrikar Dronamraju 
658225466f1SSrikar Dronamraju 	if (pev->uprobes)
659225466f1SSrikar Dronamraju 		return convert_name_to_addr(pev, target);
660225466f1SSrikar Dronamraju 
6614b4da7f7SMasami Hiramatsu 	return 0;
6624b4da7f7SMasami Hiramatsu }
6634b4da7f7SMasami Hiramatsu 
664469b9b88SMasami Hiramatsu int show_line_range(struct line_range *lr __unused, const char *module __unused)
6654b4da7f7SMasami Hiramatsu {
666146a1439SMasami Hiramatsu 	pr_warning("Debuginfo-analysis is not supported.\n");
667146a1439SMasami Hiramatsu 	return -ENOSYS;
6684b4da7f7SMasami Hiramatsu }
6694b4da7f7SMasami Hiramatsu 
670cf6eb489SMasami Hiramatsu int show_available_vars(struct perf_probe_event *pevs __unused,
671469b9b88SMasami Hiramatsu 			int npevs __unused, int max_vls __unused,
672bd09d7b5SMasami Hiramatsu 			const char *module __unused,
673bd09d7b5SMasami Hiramatsu 			struct strfilter *filter __unused,
674bd09d7b5SMasami Hiramatsu 			bool externs __unused)
675cf6eb489SMasami Hiramatsu {
676cf6eb489SMasami Hiramatsu 	pr_warning("Debuginfo-analysis is not supported.\n");
677cf6eb489SMasami Hiramatsu 	return -ENOSYS;
678cf6eb489SMasami Hiramatsu }
679e0faa8d3SMasami Hiramatsu #endif
680e0faa8d3SMasami Hiramatsu 
68121dd9ae5SFranck Bui-Huu static int parse_line_num(char **ptr, int *val, const char *what)
68221dd9ae5SFranck Bui-Huu {
68321dd9ae5SFranck Bui-Huu 	const char *start = *ptr;
68421dd9ae5SFranck Bui-Huu 
68521dd9ae5SFranck Bui-Huu 	errno = 0;
68621dd9ae5SFranck Bui-Huu 	*val = strtol(*ptr, ptr, 0);
68721dd9ae5SFranck Bui-Huu 	if (errno || *ptr == start) {
68821dd9ae5SFranck Bui-Huu 		semantic_error("'%s' is not a valid number.\n", what);
68921dd9ae5SFranck Bui-Huu 		return -EINVAL;
69021dd9ae5SFranck Bui-Huu 	}
69121dd9ae5SFranck Bui-Huu 	return 0;
69221dd9ae5SFranck Bui-Huu }
69321dd9ae5SFranck Bui-Huu 
6949d95b580SFranck Bui-Huu /*
6959d95b580SFranck Bui-Huu  * Stuff 'lr' according to the line range described by 'arg'.
6969d95b580SFranck Bui-Huu  * The line range syntax is described by:
6979d95b580SFranck Bui-Huu  *
6989d95b580SFranck Bui-Huu  *         SRC[:SLN[+NUM|-ELN]]
699e116dfa1SMasami Hiramatsu  *         FNC[@SRC][:SLN[+NUM|-ELN]]
7009d95b580SFranck Bui-Huu  */
701146a1439SMasami Hiramatsu int parse_line_range_desc(const char *arg, struct line_range *lr)
702631c9defSMasami Hiramatsu {
703e116dfa1SMasami Hiramatsu 	char *range, *file, *name = strdup(arg);
70421dd9ae5SFranck Bui-Huu 	int err;
7059d95b580SFranck Bui-Huu 
70621dd9ae5SFranck Bui-Huu 	if (!name)
70721dd9ae5SFranck Bui-Huu 		return -ENOMEM;
70821dd9ae5SFranck Bui-Huu 
70921dd9ae5SFranck Bui-Huu 	lr->start = 0;
71021dd9ae5SFranck Bui-Huu 	lr->end = INT_MAX;
71121dd9ae5SFranck Bui-Huu 
71221dd9ae5SFranck Bui-Huu 	range = strchr(name, ':');
71321dd9ae5SFranck Bui-Huu 	if (range) {
71421dd9ae5SFranck Bui-Huu 		*range++ = '\0';
71521dd9ae5SFranck Bui-Huu 
71621dd9ae5SFranck Bui-Huu 		err = parse_line_num(&range, &lr->start, "start line");
71721dd9ae5SFranck Bui-Huu 		if (err)
71821dd9ae5SFranck Bui-Huu 			goto err;
71921dd9ae5SFranck Bui-Huu 
72021dd9ae5SFranck Bui-Huu 		if (*range == '+' || *range == '-') {
72121dd9ae5SFranck Bui-Huu 			const char c = *range++;
72221dd9ae5SFranck Bui-Huu 
72321dd9ae5SFranck Bui-Huu 			err = parse_line_num(&range, &lr->end, "end line");
72421dd9ae5SFranck Bui-Huu 			if (err)
72521dd9ae5SFranck Bui-Huu 				goto err;
72621dd9ae5SFranck Bui-Huu 
72721dd9ae5SFranck Bui-Huu 			if (c == '+') {
72821dd9ae5SFranck Bui-Huu 				lr->end += lr->start;
72921dd9ae5SFranck Bui-Huu 				/*
730dda4ab34SMasami Hiramatsu 				 * Adjust the number of lines here.
731dda4ab34SMasami Hiramatsu 				 * If the number of lines == 1, the
732dda4ab34SMasami Hiramatsu 				 * the end of line should be equal to
733dda4ab34SMasami Hiramatsu 				 * the start of line.
734dda4ab34SMasami Hiramatsu 				 */
73521dd9ae5SFranck Bui-Huu 				lr->end--;
73621dd9ae5SFranck Bui-Huu 			}
73721dd9ae5SFranck Bui-Huu 		}
73821dd9ae5SFranck Bui-Huu 
739d3b63d7aSMasami Hiramatsu 		pr_debug("Line range is %d to %d\n", lr->start, lr->end);
74021dd9ae5SFranck Bui-Huu 
74121dd9ae5SFranck Bui-Huu 		err = -EINVAL;
742d3b63d7aSMasami Hiramatsu 		if (lr->start > lr->end) {
743631c9defSMasami Hiramatsu 			semantic_error("Start line must be smaller"
744146a1439SMasami Hiramatsu 				       " than end line.\n");
74521dd9ae5SFranck Bui-Huu 			goto err;
746146a1439SMasami Hiramatsu 		}
74721dd9ae5SFranck Bui-Huu 		if (*range != '\0') {
74821dd9ae5SFranck Bui-Huu 			semantic_error("Tailing with invalid str '%s'.\n", range);
74921dd9ae5SFranck Bui-Huu 			goto err;
750146a1439SMasami Hiramatsu 		}
751d3b63d7aSMasami Hiramatsu 	}
75202b95dadSMasami Hiramatsu 
753e116dfa1SMasami Hiramatsu 	file = strchr(name, '@');
754e116dfa1SMasami Hiramatsu 	if (file) {
755e116dfa1SMasami Hiramatsu 		*file = '\0';
756e116dfa1SMasami Hiramatsu 		lr->file = strdup(++file);
757e116dfa1SMasami Hiramatsu 		if (lr->file == NULL) {
758e116dfa1SMasami Hiramatsu 			err = -ENOMEM;
759e116dfa1SMasami Hiramatsu 			goto err;
760e116dfa1SMasami Hiramatsu 		}
761e116dfa1SMasami Hiramatsu 		lr->function = name;
762e116dfa1SMasami Hiramatsu 	} else if (strchr(name, '.'))
76321dd9ae5SFranck Bui-Huu 		lr->file = name;
764631c9defSMasami Hiramatsu 	else
76521dd9ae5SFranck Bui-Huu 		lr->function = name;
766146a1439SMasami Hiramatsu 
767146a1439SMasami Hiramatsu 	return 0;
76821dd9ae5SFranck Bui-Huu err:
76921dd9ae5SFranck Bui-Huu 	free(name);
77021dd9ae5SFranck Bui-Huu 	return err;
771631c9defSMasami Hiramatsu }
772631c9defSMasami Hiramatsu 
773b7702a21SMasami Hiramatsu /* Check the name is good for event/group */
774b7702a21SMasami Hiramatsu static bool check_event_name(const char *name)
775b7702a21SMasami Hiramatsu {
776b7702a21SMasami Hiramatsu 	if (!isalpha(*name) && *name != '_')
777b7702a21SMasami Hiramatsu 		return false;
778b7702a21SMasami Hiramatsu 	while (*++name != '\0') {
779b7702a21SMasami Hiramatsu 		if (!isalpha(*name) && !isdigit(*name) && *name != '_')
780b7702a21SMasami Hiramatsu 			return false;
781b7702a21SMasami Hiramatsu 	}
782b7702a21SMasami Hiramatsu 	return true;
783b7702a21SMasami Hiramatsu }
784b7702a21SMasami Hiramatsu 
78550656eecSMasami Hiramatsu /* Parse probepoint definition. */
786146a1439SMasami Hiramatsu static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
78750656eecSMasami Hiramatsu {
7884235b045SMasami Hiramatsu 	struct perf_probe_point *pp = &pev->point;
78950656eecSMasami Hiramatsu 	char *ptr, *tmp;
79050656eecSMasami Hiramatsu 	char c, nc = 0;
79150656eecSMasami Hiramatsu 	/*
79250656eecSMasami Hiramatsu 	 * <Syntax>
7932a9c8c36SMasami Hiramatsu 	 * perf probe [EVENT=]SRC[:LN|;PTN]
7942a9c8c36SMasami Hiramatsu 	 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
795af663d75SMasami Hiramatsu 	 *
796af663d75SMasami Hiramatsu 	 * TODO:Group name support
79750656eecSMasami Hiramatsu 	 */
79850656eecSMasami Hiramatsu 
7992a9c8c36SMasami Hiramatsu 	ptr = strpbrk(arg, ";=@+%");
8002a9c8c36SMasami Hiramatsu 	if (ptr && *ptr == '=') {	/* Event name */
801af663d75SMasami Hiramatsu 		*ptr = '\0';
802af663d75SMasami Hiramatsu 		tmp = ptr + 1;
803146a1439SMasami Hiramatsu 		if (strchr(arg, ':')) {
804146a1439SMasami Hiramatsu 			semantic_error("Group name is not supported yet.\n");
805146a1439SMasami Hiramatsu 			return -ENOTSUP;
806146a1439SMasami Hiramatsu 		}
807146a1439SMasami Hiramatsu 		if (!check_event_name(arg)) {
808b7702a21SMasami Hiramatsu 			semantic_error("%s is bad for event name -it must "
809146a1439SMasami Hiramatsu 				       "follow C symbol-naming rule.\n", arg);
810146a1439SMasami Hiramatsu 			return -EINVAL;
811146a1439SMasami Hiramatsu 		}
81202b95dadSMasami Hiramatsu 		pev->event = strdup(arg);
81302b95dadSMasami Hiramatsu 		if (pev->event == NULL)
81402b95dadSMasami Hiramatsu 			return -ENOMEM;
8154235b045SMasami Hiramatsu 		pev->group = NULL;
816af663d75SMasami Hiramatsu 		arg = tmp;
817af663d75SMasami Hiramatsu 	}
818af663d75SMasami Hiramatsu 
8192a9c8c36SMasami Hiramatsu 	ptr = strpbrk(arg, ";:+@%");
82050656eecSMasami Hiramatsu 	if (ptr) {
82150656eecSMasami Hiramatsu 		nc = *ptr;
82250656eecSMasami Hiramatsu 		*ptr++ = '\0';
82350656eecSMasami Hiramatsu 	}
82450656eecSMasami Hiramatsu 
82502b95dadSMasami Hiramatsu 	tmp = strdup(arg);
82602b95dadSMasami Hiramatsu 	if (tmp == NULL)
82702b95dadSMasami Hiramatsu 		return -ENOMEM;
82802b95dadSMasami Hiramatsu 
82950656eecSMasami Hiramatsu 	/* Check arg is function or file and copy it */
83002b95dadSMasami Hiramatsu 	if (strchr(tmp, '.'))	/* File */
83102b95dadSMasami Hiramatsu 		pp->file = tmp;
83250656eecSMasami Hiramatsu 	else			/* Function */
83302b95dadSMasami Hiramatsu 		pp->function = tmp;
83450656eecSMasami Hiramatsu 
83550656eecSMasami Hiramatsu 	/* Parse other options */
83650656eecSMasami Hiramatsu 	while (ptr) {
83750656eecSMasami Hiramatsu 		arg = ptr;
83850656eecSMasami Hiramatsu 		c = nc;
8392a9c8c36SMasami Hiramatsu 		if (c == ';') {	/* Lazy pattern must be the last part */
84002b95dadSMasami Hiramatsu 			pp->lazy_line = strdup(arg);
84102b95dadSMasami Hiramatsu 			if (pp->lazy_line == NULL)
84202b95dadSMasami Hiramatsu 				return -ENOMEM;
8432a9c8c36SMasami Hiramatsu 			break;
8442a9c8c36SMasami Hiramatsu 		}
8452a9c8c36SMasami Hiramatsu 		ptr = strpbrk(arg, ";:+@%");
84650656eecSMasami Hiramatsu 		if (ptr) {
84750656eecSMasami Hiramatsu 			nc = *ptr;
84850656eecSMasami Hiramatsu 			*ptr++ = '\0';
84950656eecSMasami Hiramatsu 		}
85050656eecSMasami Hiramatsu 		switch (c) {
85150656eecSMasami Hiramatsu 		case ':':	/* Line number */
85250656eecSMasami Hiramatsu 			pp->line = strtoul(arg, &tmp, 0);
853146a1439SMasami Hiramatsu 			if (*tmp != '\0') {
8542a9c8c36SMasami Hiramatsu 				semantic_error("There is non-digit char"
855146a1439SMasami Hiramatsu 					       " in line number.\n");
856146a1439SMasami Hiramatsu 				return -EINVAL;
857146a1439SMasami Hiramatsu 			}
85850656eecSMasami Hiramatsu 			break;
85950656eecSMasami Hiramatsu 		case '+':	/* Byte offset from a symbol */
86050656eecSMasami Hiramatsu 			pp->offset = strtoul(arg, &tmp, 0);
861146a1439SMasami Hiramatsu 			if (*tmp != '\0') {
8622a9c8c36SMasami Hiramatsu 				semantic_error("There is non-digit character"
863146a1439SMasami Hiramatsu 						" in offset.\n");
864146a1439SMasami Hiramatsu 				return -EINVAL;
865146a1439SMasami Hiramatsu 			}
86650656eecSMasami Hiramatsu 			break;
86750656eecSMasami Hiramatsu 		case '@':	/* File name */
868146a1439SMasami Hiramatsu 			if (pp->file) {
869146a1439SMasami Hiramatsu 				semantic_error("SRC@SRC is not allowed.\n");
870146a1439SMasami Hiramatsu 				return -EINVAL;
871146a1439SMasami Hiramatsu 			}
87202b95dadSMasami Hiramatsu 			pp->file = strdup(arg);
87302b95dadSMasami Hiramatsu 			if (pp->file == NULL)
87402b95dadSMasami Hiramatsu 				return -ENOMEM;
87550656eecSMasami Hiramatsu 			break;
87650656eecSMasami Hiramatsu 		case '%':	/* Probe places */
87750656eecSMasami Hiramatsu 			if (strcmp(arg, "return") == 0) {
87850656eecSMasami Hiramatsu 				pp->retprobe = 1;
879146a1439SMasami Hiramatsu 			} else {	/* Others not supported yet */
880146a1439SMasami Hiramatsu 				semantic_error("%%%s is not supported.\n", arg);
881146a1439SMasami Hiramatsu 				return -ENOTSUP;
882146a1439SMasami Hiramatsu 			}
88350656eecSMasami Hiramatsu 			break;
884146a1439SMasami Hiramatsu 		default:	/* Buggy case */
885146a1439SMasami Hiramatsu 			pr_err("This program has a bug at %s:%d.\n",
886146a1439SMasami Hiramatsu 				__FILE__, __LINE__);
887146a1439SMasami Hiramatsu 			return -ENOTSUP;
88850656eecSMasami Hiramatsu 			break;
88950656eecSMasami Hiramatsu 		}
89050656eecSMasami Hiramatsu 	}
89150656eecSMasami Hiramatsu 
89250656eecSMasami Hiramatsu 	/* Exclusion check */
893146a1439SMasami Hiramatsu 	if (pp->lazy_line && pp->line) {
8940e43e5d2SMasami Hiramatsu 		semantic_error("Lazy pattern can't be used with"
8950e43e5d2SMasami Hiramatsu 			       " line number.\n");
896146a1439SMasami Hiramatsu 		return -EINVAL;
897146a1439SMasami Hiramatsu 	}
8982a9c8c36SMasami Hiramatsu 
899146a1439SMasami Hiramatsu 	if (pp->lazy_line && pp->offset) {
9000e43e5d2SMasami Hiramatsu 		semantic_error("Lazy pattern can't be used with offset.\n");
901146a1439SMasami Hiramatsu 		return -EINVAL;
902146a1439SMasami Hiramatsu 	}
9032a9c8c36SMasami Hiramatsu 
904146a1439SMasami Hiramatsu 	if (pp->line && pp->offset) {
9050e43e5d2SMasami Hiramatsu 		semantic_error("Offset can't be used with line number.\n");
906146a1439SMasami Hiramatsu 		return -EINVAL;
907146a1439SMasami Hiramatsu 	}
90850656eecSMasami Hiramatsu 
909146a1439SMasami Hiramatsu 	if (!pp->line && !pp->lazy_line && pp->file && !pp->function) {
9102a9c8c36SMasami Hiramatsu 		semantic_error("File always requires line number or "
9110e43e5d2SMasami Hiramatsu 			       "lazy pattern.\n");
912146a1439SMasami Hiramatsu 		return -EINVAL;
913146a1439SMasami Hiramatsu 	}
91450656eecSMasami Hiramatsu 
915146a1439SMasami Hiramatsu 	if (pp->offset && !pp->function) {
9160e43e5d2SMasami Hiramatsu 		semantic_error("Offset requires an entry function.\n");
917146a1439SMasami Hiramatsu 		return -EINVAL;
918146a1439SMasami Hiramatsu 	}
91950656eecSMasami Hiramatsu 
920146a1439SMasami Hiramatsu 	if (pp->retprobe && !pp->function) {
9210e43e5d2SMasami Hiramatsu 		semantic_error("Return probe requires an entry function.\n");
922146a1439SMasami Hiramatsu 		return -EINVAL;
923146a1439SMasami Hiramatsu 	}
92450656eecSMasami Hiramatsu 
925146a1439SMasami Hiramatsu 	if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
9262a9c8c36SMasami Hiramatsu 		semantic_error("Offset/Line/Lazy pattern can't be used with "
9270e43e5d2SMasami Hiramatsu 			       "return probe.\n");
928146a1439SMasami Hiramatsu 		return -EINVAL;
929146a1439SMasami Hiramatsu 	}
93050656eecSMasami Hiramatsu 
9314235b045SMasami Hiramatsu 	pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
9322a9c8c36SMasami Hiramatsu 		 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
9332a9c8c36SMasami Hiramatsu 		 pp->lazy_line);
934146a1439SMasami Hiramatsu 	return 0;
93550656eecSMasami Hiramatsu }
93650656eecSMasami Hiramatsu 
9377df2f329SMasami Hiramatsu /* Parse perf-probe event argument */
938146a1439SMasami Hiramatsu static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
9397df2f329SMasami Hiramatsu {
940b2a3c12bSMasami Hiramatsu 	char *tmp, *goodname;
9417df2f329SMasami Hiramatsu 	struct perf_probe_arg_field **fieldp;
9427df2f329SMasami Hiramatsu 
9437df2f329SMasami Hiramatsu 	pr_debug("parsing arg: %s into ", str);
9447df2f329SMasami Hiramatsu 
94548481938SMasami Hiramatsu 	tmp = strchr(str, '=');
94648481938SMasami Hiramatsu 	if (tmp) {
94702b95dadSMasami Hiramatsu 		arg->name = strndup(str, tmp - str);
94802b95dadSMasami Hiramatsu 		if (arg->name == NULL)
94902b95dadSMasami Hiramatsu 			return -ENOMEM;
95011a1ca35SMasami Hiramatsu 		pr_debug("name:%s ", arg->name);
95148481938SMasami Hiramatsu 		str = tmp + 1;
95248481938SMasami Hiramatsu 	}
95348481938SMasami Hiramatsu 
95411a1ca35SMasami Hiramatsu 	tmp = strchr(str, ':');
95511a1ca35SMasami Hiramatsu 	if (tmp) {	/* Type setting */
95611a1ca35SMasami Hiramatsu 		*tmp = '\0';
95702b95dadSMasami Hiramatsu 		arg->type = strdup(tmp + 1);
95802b95dadSMasami Hiramatsu 		if (arg->type == NULL)
95902b95dadSMasami Hiramatsu 			return -ENOMEM;
96011a1ca35SMasami Hiramatsu 		pr_debug("type:%s ", arg->type);
96111a1ca35SMasami Hiramatsu 	}
96211a1ca35SMasami Hiramatsu 
963b2a3c12bSMasami Hiramatsu 	tmp = strpbrk(str, "-.[");
9647df2f329SMasami Hiramatsu 	if (!is_c_varname(str) || !tmp) {
9657df2f329SMasami Hiramatsu 		/* A variable, register, symbol or special value */
96602b95dadSMasami Hiramatsu 		arg->var = strdup(str);
96702b95dadSMasami Hiramatsu 		if (arg->var == NULL)
96802b95dadSMasami Hiramatsu 			return -ENOMEM;
96948481938SMasami Hiramatsu 		pr_debug("%s\n", arg->var);
970146a1439SMasami Hiramatsu 		return 0;
9717df2f329SMasami Hiramatsu 	}
9727df2f329SMasami Hiramatsu 
973b2a3c12bSMasami Hiramatsu 	/* Structure fields or array element */
97402b95dadSMasami Hiramatsu 	arg->var = strndup(str, tmp - str);
97502b95dadSMasami Hiramatsu 	if (arg->var == NULL)
97602b95dadSMasami Hiramatsu 		return -ENOMEM;
977b2a3c12bSMasami Hiramatsu 	goodname = arg->var;
97848481938SMasami Hiramatsu 	pr_debug("%s, ", arg->var);
9797df2f329SMasami Hiramatsu 	fieldp = &arg->field;
9807df2f329SMasami Hiramatsu 
9817df2f329SMasami Hiramatsu 	do {
982e334016fSMasami Hiramatsu 		*fieldp = zalloc(sizeof(struct perf_probe_arg_field));
983e334016fSMasami Hiramatsu 		if (*fieldp == NULL)
984e334016fSMasami Hiramatsu 			return -ENOMEM;
985b2a3c12bSMasami Hiramatsu 		if (*tmp == '[') {	/* Array */
986b2a3c12bSMasami Hiramatsu 			str = tmp;
987b2a3c12bSMasami Hiramatsu 			(*fieldp)->index = strtol(str + 1, &tmp, 0);
988b2a3c12bSMasami Hiramatsu 			(*fieldp)->ref = true;
989b2a3c12bSMasami Hiramatsu 			if (*tmp != ']' || tmp == str + 1) {
990b2a3c12bSMasami Hiramatsu 				semantic_error("Array index must be a"
991b2a3c12bSMasami Hiramatsu 						" number.\n");
992b2a3c12bSMasami Hiramatsu 				return -EINVAL;
993b2a3c12bSMasami Hiramatsu 			}
994b2a3c12bSMasami Hiramatsu 			tmp++;
995b2a3c12bSMasami Hiramatsu 			if (*tmp == '\0')
996b2a3c12bSMasami Hiramatsu 				tmp = NULL;
997b2a3c12bSMasami Hiramatsu 		} else {		/* Structure */
9987df2f329SMasami Hiramatsu 			if (*tmp == '.') {
9997df2f329SMasami Hiramatsu 				str = tmp + 1;
10007df2f329SMasami Hiramatsu 				(*fieldp)->ref = false;
10017df2f329SMasami Hiramatsu 			} else if (tmp[1] == '>') {
10027df2f329SMasami Hiramatsu 				str = tmp + 2;
10037df2f329SMasami Hiramatsu 				(*fieldp)->ref = true;
1004146a1439SMasami Hiramatsu 			} else {
1005b2a3c12bSMasami Hiramatsu 				semantic_error("Argument parse error: %s\n",
1006b2a3c12bSMasami Hiramatsu 					       str);
1007146a1439SMasami Hiramatsu 				return -EINVAL;
1008146a1439SMasami Hiramatsu 			}
1009b2a3c12bSMasami Hiramatsu 			tmp = strpbrk(str, "-.[");
1010b2a3c12bSMasami Hiramatsu 		}
10117df2f329SMasami Hiramatsu 		if (tmp) {
101202b95dadSMasami Hiramatsu 			(*fieldp)->name = strndup(str, tmp - str);
101302b95dadSMasami Hiramatsu 			if ((*fieldp)->name == NULL)
101402b95dadSMasami Hiramatsu 				return -ENOMEM;
1015b2a3c12bSMasami Hiramatsu 			if (*str != '[')
1016b2a3c12bSMasami Hiramatsu 				goodname = (*fieldp)->name;
10177df2f329SMasami Hiramatsu 			pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
10187df2f329SMasami Hiramatsu 			fieldp = &(*fieldp)->next;
10197df2f329SMasami Hiramatsu 		}
10207df2f329SMasami Hiramatsu 	} while (tmp);
102102b95dadSMasami Hiramatsu 	(*fieldp)->name = strdup(str);
102202b95dadSMasami Hiramatsu 	if ((*fieldp)->name == NULL)
102302b95dadSMasami Hiramatsu 		return -ENOMEM;
1024b2a3c12bSMasami Hiramatsu 	if (*str != '[')
1025b2a3c12bSMasami Hiramatsu 		goodname = (*fieldp)->name;
10267df2f329SMasami Hiramatsu 	pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
1027df0faf4bSMasami Hiramatsu 
1028b2a3c12bSMasami Hiramatsu 	/* If no name is specified, set the last field name (not array index)*/
102902b95dadSMasami Hiramatsu 	if (!arg->name) {
1030b2a3c12bSMasami Hiramatsu 		arg->name = strdup(goodname);
103102b95dadSMasami Hiramatsu 		if (arg->name == NULL)
103202b95dadSMasami Hiramatsu 			return -ENOMEM;
103302b95dadSMasami Hiramatsu 	}
1034146a1439SMasami Hiramatsu 	return 0;
10357df2f329SMasami Hiramatsu }
10367df2f329SMasami Hiramatsu 
10374235b045SMasami Hiramatsu /* Parse perf-probe event command */
1038146a1439SMasami Hiramatsu int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
103950656eecSMasami Hiramatsu {
1040e1c01d61SMasami Hiramatsu 	char **argv;
1041146a1439SMasami Hiramatsu 	int argc, i, ret = 0;
1042fac13fd5SMasami Hiramatsu 
10434235b045SMasami Hiramatsu 	argv = argv_split(cmd, &argc);
1044146a1439SMasami Hiramatsu 	if (!argv) {
1045146a1439SMasami Hiramatsu 		pr_debug("Failed to split arguments.\n");
1046146a1439SMasami Hiramatsu 		return -ENOMEM;
1047146a1439SMasami Hiramatsu 	}
1048146a1439SMasami Hiramatsu 	if (argc - 1 > MAX_PROBE_ARGS) {
1049146a1439SMasami Hiramatsu 		semantic_error("Too many probe arguments (%d).\n", argc - 1);
1050146a1439SMasami Hiramatsu 		ret = -ERANGE;
1051146a1439SMasami Hiramatsu 		goto out;
1052146a1439SMasami Hiramatsu 	}
105350656eecSMasami Hiramatsu 	/* Parse probe point */
1054146a1439SMasami Hiramatsu 	ret = parse_perf_probe_point(argv[0], pev);
1055146a1439SMasami Hiramatsu 	if (ret < 0)
1056146a1439SMasami Hiramatsu 		goto out;
105750656eecSMasami Hiramatsu 
1058e1c01d61SMasami Hiramatsu 	/* Copy arguments and ensure return probe has no C argument */
10594235b045SMasami Hiramatsu 	pev->nargs = argc - 1;
1060e334016fSMasami Hiramatsu 	pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
1061e334016fSMasami Hiramatsu 	if (pev->args == NULL) {
1062e334016fSMasami Hiramatsu 		ret = -ENOMEM;
1063e334016fSMasami Hiramatsu 		goto out;
1064e334016fSMasami Hiramatsu 	}
1065146a1439SMasami Hiramatsu 	for (i = 0; i < pev->nargs && ret >= 0; i++) {
1066146a1439SMasami Hiramatsu 		ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]);
1067146a1439SMasami Hiramatsu 		if (ret >= 0 &&
1068146a1439SMasami Hiramatsu 		    is_c_varname(pev->args[i].var) && pev->point.retprobe) {
10694235b045SMasami Hiramatsu 			semantic_error("You can't specify local variable for"
1070146a1439SMasami Hiramatsu 				       " kretprobe.\n");
1071146a1439SMasami Hiramatsu 			ret = -EINVAL;
1072e1c01d61SMasami Hiramatsu 		}
1073146a1439SMasami Hiramatsu 	}
1074146a1439SMasami Hiramatsu out:
1075e1c01d61SMasami Hiramatsu 	argv_free(argv);
1076146a1439SMasami Hiramatsu 
1077146a1439SMasami Hiramatsu 	return ret;
107850656eecSMasami Hiramatsu }
107950656eecSMasami Hiramatsu 
10804235b045SMasami Hiramatsu /* Return true if this perf_probe_event requires debuginfo */
10814235b045SMasami Hiramatsu bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
10824de189feSMasami Hiramatsu {
10834235b045SMasami Hiramatsu 	int i;
10844235b045SMasami Hiramatsu 
10854235b045SMasami Hiramatsu 	if (pev->point.file || pev->point.line || pev->point.lazy_line)
10864235b045SMasami Hiramatsu 		return true;
10874235b045SMasami Hiramatsu 
10884235b045SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++)
108948481938SMasami Hiramatsu 		if (is_c_varname(pev->args[i].var))
10904235b045SMasami Hiramatsu 			return true;
10914235b045SMasami Hiramatsu 
10924235b045SMasami Hiramatsu 	return false;
10934235b045SMasami Hiramatsu }
10944235b045SMasami Hiramatsu 
10950e60836bSSrikar Dronamraju /* Parse probe_events event into struct probe_point */
10960e60836bSSrikar Dronamraju static int parse_probe_trace_command(const char *cmd,
10970e60836bSSrikar Dronamraju 				     struct probe_trace_event *tev)
10984235b045SMasami Hiramatsu {
10990e60836bSSrikar Dronamraju 	struct probe_trace_point *tp = &tev->point;
11004de189feSMasami Hiramatsu 	char pr;
11014de189feSMasami Hiramatsu 	char *p;
11024de189feSMasami Hiramatsu 	int ret, i, argc;
11034de189feSMasami Hiramatsu 	char **argv;
11044de189feSMasami Hiramatsu 
11050e60836bSSrikar Dronamraju 	pr_debug("Parsing probe_events: %s\n", cmd);
11064235b045SMasami Hiramatsu 	argv = argv_split(cmd, &argc);
1107146a1439SMasami Hiramatsu 	if (!argv) {
1108146a1439SMasami Hiramatsu 		pr_debug("Failed to split arguments.\n");
1109146a1439SMasami Hiramatsu 		return -ENOMEM;
1110146a1439SMasami Hiramatsu 	}
1111146a1439SMasami Hiramatsu 	if (argc < 2) {
1112146a1439SMasami Hiramatsu 		semantic_error("Too few probe arguments.\n");
1113146a1439SMasami Hiramatsu 		ret = -ERANGE;
1114146a1439SMasami Hiramatsu 		goto out;
1115146a1439SMasami Hiramatsu 	}
11164de189feSMasami Hiramatsu 
11174de189feSMasami Hiramatsu 	/* Scan event and group name. */
111893aaa45aSLiming Wang 	ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]",
11194235b045SMasami Hiramatsu 		     &pr, (float *)(void *)&tev->group,
11204235b045SMasami Hiramatsu 		     (float *)(void *)&tev->event);
1121146a1439SMasami Hiramatsu 	if (ret != 3) {
1122146a1439SMasami Hiramatsu 		semantic_error("Failed to parse event name: %s\n", argv[0]);
1123146a1439SMasami Hiramatsu 		ret = -EINVAL;
1124146a1439SMasami Hiramatsu 		goto out;
1125146a1439SMasami Hiramatsu 	}
11264235b045SMasami Hiramatsu 	pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr);
11274de189feSMasami Hiramatsu 
11284235b045SMasami Hiramatsu 	tp->retprobe = (pr == 'r');
11294de189feSMasami Hiramatsu 
1130190b57fcSMasami Hiramatsu 	/* Scan module name(if there), function name and offset */
1131190b57fcSMasami Hiramatsu 	p = strchr(argv[1], ':');
1132190b57fcSMasami Hiramatsu 	if (p) {
1133190b57fcSMasami Hiramatsu 		tp->module = strndup(argv[1], p - argv[1]);
1134190b57fcSMasami Hiramatsu 		p++;
1135190b57fcSMasami Hiramatsu 	} else
1136190b57fcSMasami Hiramatsu 		p = argv[1];
1137190b57fcSMasami Hiramatsu 	ret = sscanf(p, "%a[^+]+%lu", (float *)(void *)&tp->symbol,
11384235b045SMasami Hiramatsu 		     &tp->offset);
11394de189feSMasami Hiramatsu 	if (ret == 1)
11404235b045SMasami Hiramatsu 		tp->offset = 0;
11414de189feSMasami Hiramatsu 
11424235b045SMasami Hiramatsu 	tev->nargs = argc - 2;
11430e60836bSSrikar Dronamraju 	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
1144e334016fSMasami Hiramatsu 	if (tev->args == NULL) {
1145e334016fSMasami Hiramatsu 		ret = -ENOMEM;
1146e334016fSMasami Hiramatsu 		goto out;
1147e334016fSMasami Hiramatsu 	}
11484235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
11494de189feSMasami Hiramatsu 		p = strchr(argv[i + 2], '=');
11504de189feSMasami Hiramatsu 		if (p)	/* We don't need which register is assigned. */
11514235b045SMasami Hiramatsu 			*p++ = '\0';
11524235b045SMasami Hiramatsu 		else
11534235b045SMasami Hiramatsu 			p = argv[i + 2];
115402b95dadSMasami Hiramatsu 		tev->args[i].name = strdup(argv[i + 2]);
11554235b045SMasami Hiramatsu 		/* TODO: parse regs and offset */
115602b95dadSMasami Hiramatsu 		tev->args[i].value = strdup(p);
115702b95dadSMasami Hiramatsu 		if (tev->args[i].name == NULL || tev->args[i].value == NULL) {
115802b95dadSMasami Hiramatsu 			ret = -ENOMEM;
115902b95dadSMasami Hiramatsu 			goto out;
116002b95dadSMasami Hiramatsu 		}
11614de189feSMasami Hiramatsu 	}
1162146a1439SMasami Hiramatsu 	ret = 0;
1163146a1439SMasami Hiramatsu out:
11644de189feSMasami Hiramatsu 	argv_free(argv);
1165146a1439SMasami Hiramatsu 	return ret;
11664de189feSMasami Hiramatsu }
11674de189feSMasami Hiramatsu 
11687df2f329SMasami Hiramatsu /* Compose only probe arg */
11697df2f329SMasami Hiramatsu int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
11707df2f329SMasami Hiramatsu {
11717df2f329SMasami Hiramatsu 	struct perf_probe_arg_field *field = pa->field;
11727df2f329SMasami Hiramatsu 	int ret;
11737df2f329SMasami Hiramatsu 	char *tmp = buf;
11747df2f329SMasami Hiramatsu 
117548481938SMasami Hiramatsu 	if (pa->name && pa->var)
117648481938SMasami Hiramatsu 		ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var);
117748481938SMasami Hiramatsu 	else
117848481938SMasami Hiramatsu 		ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var);
11797df2f329SMasami Hiramatsu 	if (ret <= 0)
11807df2f329SMasami Hiramatsu 		goto error;
11817df2f329SMasami Hiramatsu 	tmp += ret;
11827df2f329SMasami Hiramatsu 	len -= ret;
11837df2f329SMasami Hiramatsu 
11847df2f329SMasami Hiramatsu 	while (field) {
1185b2a3c12bSMasami Hiramatsu 		if (field->name[0] == '[')
1186b2a3c12bSMasami Hiramatsu 			ret = e_snprintf(tmp, len, "%s", field->name);
1187b2a3c12bSMasami Hiramatsu 		else
1188b2a3c12bSMasami Hiramatsu 			ret = e_snprintf(tmp, len, "%s%s",
1189b2a3c12bSMasami Hiramatsu 					 field->ref ? "->" : ".", field->name);
11907df2f329SMasami Hiramatsu 		if (ret <= 0)
11917df2f329SMasami Hiramatsu 			goto error;
11927df2f329SMasami Hiramatsu 		tmp += ret;
11937df2f329SMasami Hiramatsu 		len -= ret;
11947df2f329SMasami Hiramatsu 		field = field->next;
11957df2f329SMasami Hiramatsu 	}
119611a1ca35SMasami Hiramatsu 
119711a1ca35SMasami Hiramatsu 	if (pa->type) {
119811a1ca35SMasami Hiramatsu 		ret = e_snprintf(tmp, len, ":%s", pa->type);
119911a1ca35SMasami Hiramatsu 		if (ret <= 0)
120011a1ca35SMasami Hiramatsu 			goto error;
120111a1ca35SMasami Hiramatsu 		tmp += ret;
120211a1ca35SMasami Hiramatsu 		len -= ret;
120311a1ca35SMasami Hiramatsu 	}
120411a1ca35SMasami Hiramatsu 
12057df2f329SMasami Hiramatsu 	return tmp - buf;
12067df2f329SMasami Hiramatsu error:
12070e43e5d2SMasami Hiramatsu 	pr_debug("Failed to synthesize perf probe argument: %s\n",
1208146a1439SMasami Hiramatsu 		 strerror(-ret));
1209146a1439SMasami Hiramatsu 	return ret;
12107df2f329SMasami Hiramatsu }
12117df2f329SMasami Hiramatsu 
12124235b045SMasami Hiramatsu /* Compose only probe point (not argument) */
12134235b045SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
121450656eecSMasami Hiramatsu {
1215fb1587d8SMasami Hiramatsu 	char *buf, *tmp;
1216fb1587d8SMasami Hiramatsu 	char offs[32] = "", line[32] = "", file[32] = "";
1217fb1587d8SMasami Hiramatsu 	int ret, len;
121850656eecSMasami Hiramatsu 
1219e334016fSMasami Hiramatsu 	buf = zalloc(MAX_CMDLEN);
1220e334016fSMasami Hiramatsu 	if (buf == NULL) {
1221e334016fSMasami Hiramatsu 		ret = -ENOMEM;
1222e334016fSMasami Hiramatsu 		goto error;
1223e334016fSMasami Hiramatsu 	}
12244de189feSMasami Hiramatsu 	if (pp->offset) {
1225fb1587d8SMasami Hiramatsu 		ret = e_snprintf(offs, 32, "+%lu", pp->offset);
12264de189feSMasami Hiramatsu 		if (ret <= 0)
12274de189feSMasami Hiramatsu 			goto error;
12284de189feSMasami Hiramatsu 	}
12294de189feSMasami Hiramatsu 	if (pp->line) {
1230fb1587d8SMasami Hiramatsu 		ret = e_snprintf(line, 32, ":%d", pp->line);
1231fb1587d8SMasami Hiramatsu 		if (ret <= 0)
1232fb1587d8SMasami Hiramatsu 			goto error;
1233fb1587d8SMasami Hiramatsu 	}
1234fb1587d8SMasami Hiramatsu 	if (pp->file) {
123532ae2adeSFranck Bui-Huu 		tmp = pp->file;
123632ae2adeSFranck Bui-Huu 		len = strlen(tmp);
123732ae2adeSFranck Bui-Huu 		if (len > 30) {
123832ae2adeSFranck Bui-Huu 			tmp = strchr(pp->file + len - 30, '/');
123932ae2adeSFranck Bui-Huu 			tmp = tmp ? tmp + 1 : pp->file + len - 30;
124032ae2adeSFranck Bui-Huu 		}
124132ae2adeSFranck Bui-Huu 		ret = e_snprintf(file, 32, "@%s", tmp);
12424de189feSMasami Hiramatsu 		if (ret <= 0)
12434de189feSMasami Hiramatsu 			goto error;
12444de189feSMasami Hiramatsu 	}
12454de189feSMasami Hiramatsu 
12464de189feSMasami Hiramatsu 	if (pp->function)
1247fb1587d8SMasami Hiramatsu 		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function,
1248fb1587d8SMasami Hiramatsu 				 offs, pp->retprobe ? "%return" : "", line,
1249fb1587d8SMasami Hiramatsu 				 file);
12504de189feSMasami Hiramatsu 	else
1251fb1587d8SMasami Hiramatsu 		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line);
12524235b045SMasami Hiramatsu 	if (ret <= 0)
12534235b045SMasami Hiramatsu 		goto error;
12544235b045SMasami Hiramatsu 
12554235b045SMasami Hiramatsu 	return buf;
12564235b045SMasami Hiramatsu error:
12570e43e5d2SMasami Hiramatsu 	pr_debug("Failed to synthesize perf probe point: %s\n",
1258146a1439SMasami Hiramatsu 		 strerror(-ret));
1259e334016fSMasami Hiramatsu 	if (buf)
1260146a1439SMasami Hiramatsu 		free(buf);
1261146a1439SMasami Hiramatsu 	return NULL;
12624235b045SMasami Hiramatsu }
12634235b045SMasami Hiramatsu 
12644235b045SMasami Hiramatsu #if 0
12654235b045SMasami Hiramatsu char *synthesize_perf_probe_command(struct perf_probe_event *pev)
12664235b045SMasami Hiramatsu {
12674235b045SMasami Hiramatsu 	char *buf;
12684235b045SMasami Hiramatsu 	int i, len, ret;
12694235b045SMasami Hiramatsu 
12704235b045SMasami Hiramatsu 	buf = synthesize_perf_probe_point(&pev->point);
12714235b045SMasami Hiramatsu 	if (!buf)
12724235b045SMasami Hiramatsu 		return NULL;
12734235b045SMasami Hiramatsu 
12744235b045SMasami Hiramatsu 	len = strlen(buf);
12754235b045SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++) {
12764235b045SMasami Hiramatsu 		ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
12774235b045SMasami Hiramatsu 				 pev->args[i].name);
12787ef17aafSMasami Hiramatsu 		if (ret <= 0) {
12794235b045SMasami Hiramatsu 			free(buf);
12804235b045SMasami Hiramatsu 			return NULL;
12817ef17aafSMasami Hiramatsu 		}
12824235b045SMasami Hiramatsu 		len += ret;
12837ef17aafSMasami Hiramatsu 	}
128450656eecSMasami Hiramatsu 
12854235b045SMasami Hiramatsu 	return buf;
12864235b045SMasami Hiramatsu }
12874235b045SMasami Hiramatsu #endif
12884235b045SMasami Hiramatsu 
12890e60836bSSrikar Dronamraju static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
12904235b045SMasami Hiramatsu 					     char **buf, size_t *buflen,
12914235b045SMasami Hiramatsu 					     int depth)
12927ef17aafSMasami Hiramatsu {
12934235b045SMasami Hiramatsu 	int ret;
12944235b045SMasami Hiramatsu 	if (ref->next) {
12950e60836bSSrikar Dronamraju 		depth = __synthesize_probe_trace_arg_ref(ref->next, buf,
12964235b045SMasami Hiramatsu 							 buflen, depth + 1);
12974235b045SMasami Hiramatsu 		if (depth < 0)
12984235b045SMasami Hiramatsu 			goto out;
12994235b045SMasami Hiramatsu 	}
13004235b045SMasami Hiramatsu 
13014235b045SMasami Hiramatsu 	ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset);
13024235b045SMasami Hiramatsu 	if (ret < 0)
13034235b045SMasami Hiramatsu 		depth = ret;
13044235b045SMasami Hiramatsu 	else {
13054235b045SMasami Hiramatsu 		*buf += ret;
13064235b045SMasami Hiramatsu 		*buflen -= ret;
13074235b045SMasami Hiramatsu 	}
13084235b045SMasami Hiramatsu out:
13094235b045SMasami Hiramatsu 	return depth;
13104235b045SMasami Hiramatsu 
13114235b045SMasami Hiramatsu }
13124235b045SMasami Hiramatsu 
13130e60836bSSrikar Dronamraju static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
13144235b045SMasami Hiramatsu 				       char *buf, size_t buflen)
13154235b045SMasami Hiramatsu {
13160e60836bSSrikar Dronamraju 	struct probe_trace_arg_ref *ref = arg->ref;
13174235b045SMasami Hiramatsu 	int ret, depth = 0;
13184235b045SMasami Hiramatsu 	char *tmp = buf;
13194235b045SMasami Hiramatsu 
13204235b045SMasami Hiramatsu 	/* Argument name or separator */
13214235b045SMasami Hiramatsu 	if (arg->name)
13224235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, " %s=", arg->name);
13234235b045SMasami Hiramatsu 	else
13244235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, " ");
13254235b045SMasami Hiramatsu 	if (ret < 0)
13264235b045SMasami Hiramatsu 		return ret;
13274235b045SMasami Hiramatsu 	buf += ret;
13284235b045SMasami Hiramatsu 	buflen -= ret;
13294235b045SMasami Hiramatsu 
1330b7dcb857SMasami Hiramatsu 	/* Special case: @XXX */
1331b7dcb857SMasami Hiramatsu 	if (arg->value[0] == '@' && arg->ref)
1332b7dcb857SMasami Hiramatsu 			ref = ref->next;
1333b7dcb857SMasami Hiramatsu 
13344235b045SMasami Hiramatsu 	/* Dereferencing arguments */
1335b7dcb857SMasami Hiramatsu 	if (ref) {
13360e60836bSSrikar Dronamraju 		depth = __synthesize_probe_trace_arg_ref(ref, &buf,
13374235b045SMasami Hiramatsu 							  &buflen, 1);
13384235b045SMasami Hiramatsu 		if (depth < 0)
13394235b045SMasami Hiramatsu 			return depth;
13404235b045SMasami Hiramatsu 	}
13414235b045SMasami Hiramatsu 
13424235b045SMasami Hiramatsu 	/* Print argument value */
1343b7dcb857SMasami Hiramatsu 	if (arg->value[0] == '@' && arg->ref)
1344b7dcb857SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, "%s%+ld", arg->value,
1345b7dcb857SMasami Hiramatsu 				 arg->ref->offset);
1346b7dcb857SMasami Hiramatsu 	else
13474235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, "%s", arg->value);
13484235b045SMasami Hiramatsu 	if (ret < 0)
13494235b045SMasami Hiramatsu 		return ret;
13504235b045SMasami Hiramatsu 	buf += ret;
13514235b045SMasami Hiramatsu 	buflen -= ret;
13524235b045SMasami Hiramatsu 
13534235b045SMasami Hiramatsu 	/* Closing */
13544235b045SMasami Hiramatsu 	while (depth--) {
13554235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, ")");
13564235b045SMasami Hiramatsu 		if (ret < 0)
13574235b045SMasami Hiramatsu 			return ret;
13584235b045SMasami Hiramatsu 		buf += ret;
13594235b045SMasami Hiramatsu 		buflen -= ret;
13604235b045SMasami Hiramatsu 	}
13614984912eSMasami Hiramatsu 	/* Print argument type */
13624984912eSMasami Hiramatsu 	if (arg->type) {
13634984912eSMasami Hiramatsu 		ret = e_snprintf(buf, buflen, ":%s", arg->type);
13644984912eSMasami Hiramatsu 		if (ret <= 0)
13654984912eSMasami Hiramatsu 			return ret;
13664984912eSMasami Hiramatsu 		buf += ret;
13674984912eSMasami Hiramatsu 	}
13684235b045SMasami Hiramatsu 
13694235b045SMasami Hiramatsu 	return buf - tmp;
13704235b045SMasami Hiramatsu }
13714235b045SMasami Hiramatsu 
13720e60836bSSrikar Dronamraju char *synthesize_probe_trace_command(struct probe_trace_event *tev)
13734235b045SMasami Hiramatsu {
13740e60836bSSrikar Dronamraju 	struct probe_trace_point *tp = &tev->point;
13757ef17aafSMasami Hiramatsu 	char *buf;
13767ef17aafSMasami Hiramatsu 	int i, len, ret;
13777ef17aafSMasami Hiramatsu 
1378e334016fSMasami Hiramatsu 	buf = zalloc(MAX_CMDLEN);
1379e334016fSMasami Hiramatsu 	if (buf == NULL)
1380e334016fSMasami Hiramatsu 		return NULL;
1381e334016fSMasami Hiramatsu 
1382225466f1SSrikar Dronamraju 	if (tev->uprobes)
1383225466f1SSrikar Dronamraju 		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
1384225466f1SSrikar Dronamraju 				 tp->retprobe ? 'r' : 'p',
1385225466f1SSrikar Dronamraju 				 tev->group, tev->event,
1386225466f1SSrikar Dronamraju 				 tp->module, tp->symbol);
1387225466f1SSrikar Dronamraju 	else
1388190b57fcSMasami Hiramatsu 		len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
13894235b045SMasami Hiramatsu 				 tp->retprobe ? 'r' : 'p',
13904235b045SMasami Hiramatsu 				 tev->group, tev->event,
1391190b57fcSMasami Hiramatsu 				 tp->module ?: "", tp->module ? ":" : "",
13924235b045SMasami Hiramatsu 				 tp->symbol, tp->offset);
1393225466f1SSrikar Dronamraju 
13944235b045SMasami Hiramatsu 	if (len <= 0)
13954235b045SMasami Hiramatsu 		goto error;
13967ef17aafSMasami Hiramatsu 
13974235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
13980e60836bSSrikar Dronamraju 		ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
13994235b045SMasami Hiramatsu 						  MAX_CMDLEN - len);
14004de189feSMasami Hiramatsu 		if (ret <= 0)
140150656eecSMasami Hiramatsu 			goto error;
140250656eecSMasami Hiramatsu 		len += ret;
140350656eecSMasami Hiramatsu 	}
140450656eecSMasami Hiramatsu 
14054235b045SMasami Hiramatsu 	return buf;
140650656eecSMasami Hiramatsu error:
14074235b045SMasami Hiramatsu 	free(buf);
14084235b045SMasami Hiramatsu 	return NULL;
140950656eecSMasami Hiramatsu }
141050656eecSMasami Hiramatsu 
14110e60836bSSrikar Dronamraju static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1412225466f1SSrikar Dronamraju 			       struct perf_probe_event *pev, bool is_kprobe)
14134de189feSMasami Hiramatsu {
141402b95dadSMasami Hiramatsu 	char buf[64] = "";
1415146a1439SMasami Hiramatsu 	int i, ret;
14164de189feSMasami Hiramatsu 
14174b4da7f7SMasami Hiramatsu 	/* Convert event/group name */
141802b95dadSMasami Hiramatsu 	pev->event = strdup(tev->event);
141902b95dadSMasami Hiramatsu 	pev->group = strdup(tev->group);
142002b95dadSMasami Hiramatsu 	if (pev->event == NULL || pev->group == NULL)
142102b95dadSMasami Hiramatsu 		return -ENOMEM;
1422fb1587d8SMasami Hiramatsu 
14234b4da7f7SMasami Hiramatsu 	/* Convert trace_point to probe_point */
1424225466f1SSrikar Dronamraju 	if (is_kprobe)
14250e60836bSSrikar Dronamraju 		ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
1426225466f1SSrikar Dronamraju 	else
1427225466f1SSrikar Dronamraju 		ret = convert_to_perf_probe_point(&tev->point, &pev->point);
1428225466f1SSrikar Dronamraju 
1429146a1439SMasami Hiramatsu 	if (ret < 0)
1430146a1439SMasami Hiramatsu 		return ret;
14314b4da7f7SMasami Hiramatsu 
14324235b045SMasami Hiramatsu 	/* Convert trace_arg to probe_arg */
14334235b045SMasami Hiramatsu 	pev->nargs = tev->nargs;
1434e334016fSMasami Hiramatsu 	pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
1435e334016fSMasami Hiramatsu 	if (pev->args == NULL)
1436e334016fSMasami Hiramatsu 		return -ENOMEM;
143702b95dadSMasami Hiramatsu 	for (i = 0; i < tev->nargs && ret >= 0; i++) {
14384235b045SMasami Hiramatsu 		if (tev->args[i].name)
143902b95dadSMasami Hiramatsu 			pev->args[i].name = strdup(tev->args[i].name);
14404235b045SMasami Hiramatsu 		else {
14410e60836bSSrikar Dronamraju 			ret = synthesize_probe_trace_arg(&tev->args[i],
1442146a1439SMasami Hiramatsu 							  buf, 64);
144302b95dadSMasami Hiramatsu 			pev->args[i].name = strdup(buf);
144402b95dadSMasami Hiramatsu 		}
144502b95dadSMasami Hiramatsu 		if (pev->args[i].name == NULL && ret >= 0)
144602b95dadSMasami Hiramatsu 			ret = -ENOMEM;
14474de189feSMasami Hiramatsu 	}
1448146a1439SMasami Hiramatsu 
1449146a1439SMasami Hiramatsu 	if (ret < 0)
1450146a1439SMasami Hiramatsu 		clear_perf_probe_event(pev);
1451146a1439SMasami Hiramatsu 
1452146a1439SMasami Hiramatsu 	return ret;
14534235b045SMasami Hiramatsu }
14544de189feSMasami Hiramatsu 
14554235b045SMasami Hiramatsu void clear_perf_probe_event(struct perf_probe_event *pev)
14564235b045SMasami Hiramatsu {
14574235b045SMasami Hiramatsu 	struct perf_probe_point *pp = &pev->point;
14587df2f329SMasami Hiramatsu 	struct perf_probe_arg_field *field, *next;
14594235b045SMasami Hiramatsu 	int i;
14604de189feSMasami Hiramatsu 
14614235b045SMasami Hiramatsu 	if (pev->event)
14624235b045SMasami Hiramatsu 		free(pev->event);
14634235b045SMasami Hiramatsu 	if (pev->group)
14644235b045SMasami Hiramatsu 		free(pev->group);
14654235b045SMasami Hiramatsu 	if (pp->file)
14664235b045SMasami Hiramatsu 		free(pp->file);
14674235b045SMasami Hiramatsu 	if (pp->function)
14684235b045SMasami Hiramatsu 		free(pp->function);
14694235b045SMasami Hiramatsu 	if (pp->lazy_line)
14704235b045SMasami Hiramatsu 		free(pp->lazy_line);
14717df2f329SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++) {
14724235b045SMasami Hiramatsu 		if (pev->args[i].name)
14734235b045SMasami Hiramatsu 			free(pev->args[i].name);
147448481938SMasami Hiramatsu 		if (pev->args[i].var)
147548481938SMasami Hiramatsu 			free(pev->args[i].var);
147611a1ca35SMasami Hiramatsu 		if (pev->args[i].type)
147711a1ca35SMasami Hiramatsu 			free(pev->args[i].type);
14787df2f329SMasami Hiramatsu 		field = pev->args[i].field;
14797df2f329SMasami Hiramatsu 		while (field) {
14807df2f329SMasami Hiramatsu 			next = field->next;
14817df2f329SMasami Hiramatsu 			if (field->name)
14827df2f329SMasami Hiramatsu 				free(field->name);
14837df2f329SMasami Hiramatsu 			free(field);
14847df2f329SMasami Hiramatsu 			field = next;
14857df2f329SMasami Hiramatsu 		}
14867df2f329SMasami Hiramatsu 	}
14874235b045SMasami Hiramatsu 	if (pev->args)
14884235b045SMasami Hiramatsu 		free(pev->args);
14894235b045SMasami Hiramatsu 	memset(pev, 0, sizeof(*pev));
14904235b045SMasami Hiramatsu }
14914235b045SMasami Hiramatsu 
14920e60836bSSrikar Dronamraju static void clear_probe_trace_event(struct probe_trace_event *tev)
14934235b045SMasami Hiramatsu {
14940e60836bSSrikar Dronamraju 	struct probe_trace_arg_ref *ref, *next;
14954235b045SMasami Hiramatsu 	int i;
14964235b045SMasami Hiramatsu 
14974235b045SMasami Hiramatsu 	if (tev->event)
14984235b045SMasami Hiramatsu 		free(tev->event);
14994235b045SMasami Hiramatsu 	if (tev->group)
15004235b045SMasami Hiramatsu 		free(tev->group);
15014235b045SMasami Hiramatsu 	if (tev->point.symbol)
15024235b045SMasami Hiramatsu 		free(tev->point.symbol);
1503190b57fcSMasami Hiramatsu 	if (tev->point.module)
1504190b57fcSMasami Hiramatsu 		free(tev->point.module);
15054235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
15064235b045SMasami Hiramatsu 		if (tev->args[i].name)
15074235b045SMasami Hiramatsu 			free(tev->args[i].name);
15084235b045SMasami Hiramatsu 		if (tev->args[i].value)
15094235b045SMasami Hiramatsu 			free(tev->args[i].value);
15104984912eSMasami Hiramatsu 		if (tev->args[i].type)
15114984912eSMasami Hiramatsu 			free(tev->args[i].type);
15124235b045SMasami Hiramatsu 		ref = tev->args[i].ref;
15134235b045SMasami Hiramatsu 		while (ref) {
15144235b045SMasami Hiramatsu 			next = ref->next;
15154235b045SMasami Hiramatsu 			free(ref);
15164235b045SMasami Hiramatsu 			ref = next;
15174235b045SMasami Hiramatsu 		}
15184235b045SMasami Hiramatsu 	}
15194235b045SMasami Hiramatsu 	if (tev->args)
15204235b045SMasami Hiramatsu 		free(tev->args);
15214235b045SMasami Hiramatsu 	memset(tev, 0, sizeof(*tev));
15224de189feSMasami Hiramatsu }
15234de189feSMasami Hiramatsu 
1524225466f1SSrikar Dronamraju static void print_warn_msg(const char *file, bool is_kprobe)
1525225466f1SSrikar Dronamraju {
1526225466f1SSrikar Dronamraju 
1527225466f1SSrikar Dronamraju 	if (errno == ENOENT) {
1528225466f1SSrikar Dronamraju 		const char *config;
1529225466f1SSrikar Dronamraju 
1530225466f1SSrikar Dronamraju 		if (!is_kprobe)
1531225466f1SSrikar Dronamraju 			config = "CONFIG_UPROBE_EVENTS";
1532225466f1SSrikar Dronamraju 		else
1533225466f1SSrikar Dronamraju 			config = "CONFIG_KPROBE_EVENTS";
1534225466f1SSrikar Dronamraju 
1535225466f1SSrikar Dronamraju 		pr_warning("%s file does not exist - please rebuild kernel"
1536225466f1SSrikar Dronamraju 				" with %s.\n", file, config);
1537225466f1SSrikar Dronamraju 	} else
1538225466f1SSrikar Dronamraju 		pr_warning("Failed to open %s file: %s\n", file,
1539225466f1SSrikar Dronamraju 				strerror(errno));
1540225466f1SSrikar Dronamraju }
1541225466f1SSrikar Dronamraju 
1542225466f1SSrikar Dronamraju static int open_probe_events(const char *trace_file, bool readwrite,
1543225466f1SSrikar Dronamraju 				bool is_kprobe)
15444de189feSMasami Hiramatsu {
15454de189feSMasami Hiramatsu 	char buf[PATH_MAX];
15467ca5989dSMasami Hiramatsu 	const char *__debugfs;
15474de189feSMasami Hiramatsu 	int ret;
15484de189feSMasami Hiramatsu 
15497ca5989dSMasami Hiramatsu 	__debugfs = debugfs_find_mountpoint();
15507ca5989dSMasami Hiramatsu 	if (__debugfs == NULL) {
15517ca5989dSMasami Hiramatsu 		pr_warning("Debugfs is not mounted.\n");
15527ca5989dSMasami Hiramatsu 		return -ENOENT;
15537ca5989dSMasami Hiramatsu 	}
15547ca5989dSMasami Hiramatsu 
1555225466f1SSrikar Dronamraju 	ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
1556146a1439SMasami Hiramatsu 	if (ret >= 0) {
15577ca5989dSMasami Hiramatsu 		pr_debug("Opening %s write=%d\n", buf, readwrite);
1558f4d7da49SMasami Hiramatsu 		if (readwrite && !probe_event_dry_run)
1559f4d7da49SMasami Hiramatsu 			ret = open(buf, O_RDWR, O_APPEND);
1560f4d7da49SMasami Hiramatsu 		else
1561f4d7da49SMasami Hiramatsu 			ret = open(buf, O_RDONLY, 0);
1562f4d7da49SMasami Hiramatsu 
1563225466f1SSrikar Dronamraju 		if (ret < 0)
1564225466f1SSrikar Dronamraju 			print_warn_msg(buf, is_kprobe);
15654de189feSMasami Hiramatsu 	}
15664de189feSMasami Hiramatsu 	return ret;
15674de189feSMasami Hiramatsu }
15684de189feSMasami Hiramatsu 
1569225466f1SSrikar Dronamraju static int open_kprobe_events(bool readwrite)
1570225466f1SSrikar Dronamraju {
1571225466f1SSrikar Dronamraju 	return open_probe_events("tracing/kprobe_events", readwrite, true);
1572225466f1SSrikar Dronamraju }
1573225466f1SSrikar Dronamraju 
1574225466f1SSrikar Dronamraju static int open_uprobe_events(bool readwrite)
1575225466f1SSrikar Dronamraju {
1576225466f1SSrikar Dronamraju 	return open_probe_events("tracing/uprobe_events", readwrite, false);
1577225466f1SSrikar Dronamraju }
1578225466f1SSrikar Dronamraju 
1579225466f1SSrikar Dronamraju /* Get raw string list of current kprobe_events  or uprobe_events */
15800e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_command_rawlist(int fd)
15814de189feSMasami Hiramatsu {
15824de189feSMasami Hiramatsu 	int ret, idx;
15834de189feSMasami Hiramatsu 	FILE *fp;
15844de189feSMasami Hiramatsu 	char buf[MAX_CMDLEN];
15854de189feSMasami Hiramatsu 	char *p;
15864de189feSMasami Hiramatsu 	struct strlist *sl;
15874de189feSMasami Hiramatsu 
15884de189feSMasami Hiramatsu 	sl = strlist__new(true, NULL);
15894de189feSMasami Hiramatsu 
15904de189feSMasami Hiramatsu 	fp = fdopen(dup(fd), "r");
15914de189feSMasami Hiramatsu 	while (!feof(fp)) {
15924de189feSMasami Hiramatsu 		p = fgets(buf, MAX_CMDLEN, fp);
15934de189feSMasami Hiramatsu 		if (!p)
15944de189feSMasami Hiramatsu 			break;
15954de189feSMasami Hiramatsu 
15964de189feSMasami Hiramatsu 		idx = strlen(p) - 1;
15974de189feSMasami Hiramatsu 		if (p[idx] == '\n')
15984de189feSMasami Hiramatsu 			p[idx] = '\0';
15994de189feSMasami Hiramatsu 		ret = strlist__add(sl, buf);
1600146a1439SMasami Hiramatsu 		if (ret < 0) {
1601146a1439SMasami Hiramatsu 			pr_debug("strlist__add failed: %s\n", strerror(-ret));
1602146a1439SMasami Hiramatsu 			strlist__delete(sl);
1603146a1439SMasami Hiramatsu 			return NULL;
1604146a1439SMasami Hiramatsu 		}
16054de189feSMasami Hiramatsu 	}
16064de189feSMasami Hiramatsu 	fclose(fp);
16074de189feSMasami Hiramatsu 
16084de189feSMasami Hiramatsu 	return sl;
16094de189feSMasami Hiramatsu }
16104de189feSMasami Hiramatsu 
1611278498d4SMasami Hiramatsu /* Show an event */
1612146a1439SMasami Hiramatsu static int show_perf_probe_event(struct perf_probe_event *pev)
1613278498d4SMasami Hiramatsu {
16147e990a51SMasami Hiramatsu 	int i, ret;
1615278498d4SMasami Hiramatsu 	char buf[128];
16164235b045SMasami Hiramatsu 	char *place;
1617278498d4SMasami Hiramatsu 
16184235b045SMasami Hiramatsu 	/* Synthesize only event probe point */
16194235b045SMasami Hiramatsu 	place = synthesize_perf_probe_point(&pev->point);
1620146a1439SMasami Hiramatsu 	if (!place)
1621146a1439SMasami Hiramatsu 		return -EINVAL;
16224235b045SMasami Hiramatsu 
16234235b045SMasami Hiramatsu 	ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event);
16247e990a51SMasami Hiramatsu 	if (ret < 0)
1625146a1439SMasami Hiramatsu 		return ret;
1626146a1439SMasami Hiramatsu 
1627fb1587d8SMasami Hiramatsu 	printf("  %-20s (on %s", buf, place);
1628278498d4SMasami Hiramatsu 
16294235b045SMasami Hiramatsu 	if (pev->nargs > 0) {
1630278498d4SMasami Hiramatsu 		printf(" with");
16317df2f329SMasami Hiramatsu 		for (i = 0; i < pev->nargs; i++) {
1632146a1439SMasami Hiramatsu 			ret = synthesize_perf_probe_arg(&pev->args[i],
1633146a1439SMasami Hiramatsu 							buf, 128);
1634146a1439SMasami Hiramatsu 			if (ret < 0)
1635146a1439SMasami Hiramatsu 				break;
16367df2f329SMasami Hiramatsu 			printf(" %s", buf);
16377df2f329SMasami Hiramatsu 		}
1638278498d4SMasami Hiramatsu 	}
1639278498d4SMasami Hiramatsu 	printf(")\n");
16404235b045SMasami Hiramatsu 	free(place);
1641146a1439SMasami Hiramatsu 	return ret;
1642278498d4SMasami Hiramatsu }
1643278498d4SMasami Hiramatsu 
1644225466f1SSrikar Dronamraju static int __show_perf_probe_events(int fd, bool is_kprobe)
16454de189feSMasami Hiramatsu {
1646225466f1SSrikar Dronamraju 	int ret = 0;
16470e60836bSSrikar Dronamraju 	struct probe_trace_event tev;
16484235b045SMasami Hiramatsu 	struct perf_probe_event pev;
16494de189feSMasami Hiramatsu 	struct strlist *rawlist;
16504de189feSMasami Hiramatsu 	struct str_node *ent;
16514de189feSMasami Hiramatsu 
16524235b045SMasami Hiramatsu 	memset(&tev, 0, sizeof(tev));
16534235b045SMasami Hiramatsu 	memset(&pev, 0, sizeof(pev));
165472041334SMasami Hiramatsu 
16550e60836bSSrikar Dronamraju 	rawlist = get_probe_trace_command_rawlist(fd);
1656146a1439SMasami Hiramatsu 	if (!rawlist)
1657146a1439SMasami Hiramatsu 		return -ENOENT;
16584de189feSMasami Hiramatsu 
1659adf365f4SMasami Hiramatsu 	strlist__for_each(ent, rawlist) {
16600e60836bSSrikar Dronamraju 		ret = parse_probe_trace_command(ent->s, &tev);
1661146a1439SMasami Hiramatsu 		if (ret >= 0) {
1662225466f1SSrikar Dronamraju 			ret = convert_to_perf_probe_event(&tev, &pev,
1663225466f1SSrikar Dronamraju 								is_kprobe);
1664146a1439SMasami Hiramatsu 			if (ret >= 0)
1665146a1439SMasami Hiramatsu 				ret = show_perf_probe_event(&pev);
1666146a1439SMasami Hiramatsu 		}
16674235b045SMasami Hiramatsu 		clear_perf_probe_event(&pev);
16680e60836bSSrikar Dronamraju 		clear_probe_trace_event(&tev);
1669146a1439SMasami Hiramatsu 		if (ret < 0)
1670146a1439SMasami Hiramatsu 			break;
16714de189feSMasami Hiramatsu 	}
16724de189feSMasami Hiramatsu 	strlist__delete(rawlist);
1673146a1439SMasami Hiramatsu 
1674146a1439SMasami Hiramatsu 	return ret;
16754de189feSMasami Hiramatsu }
16764de189feSMasami Hiramatsu 
1677225466f1SSrikar Dronamraju /* List up current perf-probe events */
1678225466f1SSrikar Dronamraju int show_perf_probe_events(void)
1679225466f1SSrikar Dronamraju {
1680225466f1SSrikar Dronamraju 	int fd, ret;
1681225466f1SSrikar Dronamraju 
1682225466f1SSrikar Dronamraju 	setup_pager();
1683225466f1SSrikar Dronamraju 	fd = open_kprobe_events(false);
1684225466f1SSrikar Dronamraju 
1685225466f1SSrikar Dronamraju 	if (fd < 0)
1686225466f1SSrikar Dronamraju 		return fd;
1687225466f1SSrikar Dronamraju 
1688225466f1SSrikar Dronamraju 	ret = init_vmlinux();
1689225466f1SSrikar Dronamraju 	if (ret < 0)
1690225466f1SSrikar Dronamraju 		return ret;
1691225466f1SSrikar Dronamraju 
1692225466f1SSrikar Dronamraju 	ret = __show_perf_probe_events(fd, true);
1693225466f1SSrikar Dronamraju 	close(fd);
1694225466f1SSrikar Dronamraju 
1695225466f1SSrikar Dronamraju 	fd = open_uprobe_events(false);
1696225466f1SSrikar Dronamraju 	if (fd >= 0) {
1697225466f1SSrikar Dronamraju 		ret = __show_perf_probe_events(fd, false);
1698225466f1SSrikar Dronamraju 		close(fd);
1699225466f1SSrikar Dronamraju 	}
1700225466f1SSrikar Dronamraju 
1701225466f1SSrikar Dronamraju 	return ret;
1702225466f1SSrikar Dronamraju }
1703225466f1SSrikar Dronamraju 
1704b498ce1fSMasami Hiramatsu /* Get current perf-probe event names */
17050e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
1706b498ce1fSMasami Hiramatsu {
1707fa28244dSMasami Hiramatsu 	char buf[128];
1708b498ce1fSMasami Hiramatsu 	struct strlist *sl, *rawlist;
1709b498ce1fSMasami Hiramatsu 	struct str_node *ent;
17100e60836bSSrikar Dronamraju 	struct probe_trace_event tev;
1711146a1439SMasami Hiramatsu 	int ret = 0;
1712b498ce1fSMasami Hiramatsu 
17134235b045SMasami Hiramatsu 	memset(&tev, 0, sizeof(tev));
17140e60836bSSrikar Dronamraju 	rawlist = get_probe_trace_command_rawlist(fd);
1715e1d2017bSMasami Hiramatsu 	sl = strlist__new(true, NULL);
1716adf365f4SMasami Hiramatsu 	strlist__for_each(ent, rawlist) {
17170e60836bSSrikar Dronamraju 		ret = parse_probe_trace_command(ent->s, &tev);
1718146a1439SMasami Hiramatsu 		if (ret < 0)
1719146a1439SMasami Hiramatsu 			break;
1720fa28244dSMasami Hiramatsu 		if (include_group) {
1721146a1439SMasami Hiramatsu 			ret = e_snprintf(buf, 128, "%s:%s", tev.group,
1722146a1439SMasami Hiramatsu 					tev.event);
1723146a1439SMasami Hiramatsu 			if (ret >= 0)
1724146a1439SMasami Hiramatsu 				ret = strlist__add(sl, buf);
1725fa28244dSMasami Hiramatsu 		} else
1726146a1439SMasami Hiramatsu 			ret = strlist__add(sl, tev.event);
17270e60836bSSrikar Dronamraju 		clear_probe_trace_event(&tev);
1728146a1439SMasami Hiramatsu 		if (ret < 0)
1729146a1439SMasami Hiramatsu 			break;
1730b498ce1fSMasami Hiramatsu 	}
1731b498ce1fSMasami Hiramatsu 	strlist__delete(rawlist);
1732b498ce1fSMasami Hiramatsu 
1733146a1439SMasami Hiramatsu 	if (ret < 0) {
1734146a1439SMasami Hiramatsu 		strlist__delete(sl);
1735146a1439SMasami Hiramatsu 		return NULL;
1736146a1439SMasami Hiramatsu 	}
1737b498ce1fSMasami Hiramatsu 	return sl;
1738b498ce1fSMasami Hiramatsu }
1739b498ce1fSMasami Hiramatsu 
17400e60836bSSrikar Dronamraju static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
174150656eecSMasami Hiramatsu {
17426eca8cc3SFrederic Weisbecker 	int ret = 0;
17430e60836bSSrikar Dronamraju 	char *buf = synthesize_probe_trace_command(tev);
174450656eecSMasami Hiramatsu 
1745146a1439SMasami Hiramatsu 	if (!buf) {
17460e60836bSSrikar Dronamraju 		pr_debug("Failed to synthesize probe trace event.\n");
1747146a1439SMasami Hiramatsu 		return -EINVAL;
1748146a1439SMasami Hiramatsu 	}
1749146a1439SMasami Hiramatsu 
1750fa28244dSMasami Hiramatsu 	pr_debug("Writing event: %s\n", buf);
1751f4d7da49SMasami Hiramatsu 	if (!probe_event_dry_run) {
175250656eecSMasami Hiramatsu 		ret = write(fd, buf, strlen(buf));
175350656eecSMasami Hiramatsu 		if (ret <= 0)
1754146a1439SMasami Hiramatsu 			pr_warning("Failed to write event: %s\n",
1755146a1439SMasami Hiramatsu 				   strerror(errno));
175650656eecSMasami Hiramatsu 	}
17574235b045SMasami Hiramatsu 	free(buf);
1758146a1439SMasami Hiramatsu 	return ret;
1759f4d7da49SMasami Hiramatsu }
176050656eecSMasami Hiramatsu 
1761146a1439SMasami Hiramatsu static int get_new_event_name(char *buf, size_t len, const char *base,
1762d761b08bSMasami Hiramatsu 			      struct strlist *namelist, bool allow_suffix)
1763b498ce1fSMasami Hiramatsu {
1764b498ce1fSMasami Hiramatsu 	int i, ret;
176517f88fcdSMasami Hiramatsu 
176617f88fcdSMasami Hiramatsu 	/* Try no suffix */
176717f88fcdSMasami Hiramatsu 	ret = e_snprintf(buf, len, "%s", base);
1768146a1439SMasami Hiramatsu 	if (ret < 0) {
1769146a1439SMasami Hiramatsu 		pr_debug("snprintf() failed: %s\n", strerror(-ret));
1770146a1439SMasami Hiramatsu 		return ret;
1771146a1439SMasami Hiramatsu 	}
177217f88fcdSMasami Hiramatsu 	if (!strlist__has_entry(namelist, buf))
1773146a1439SMasami Hiramatsu 		return 0;
177417f88fcdSMasami Hiramatsu 
1775d761b08bSMasami Hiramatsu 	if (!allow_suffix) {
1776d761b08bSMasami Hiramatsu 		pr_warning("Error: event \"%s\" already exists. "
1777d761b08bSMasami Hiramatsu 			   "(Use -f to force duplicates.)\n", base);
1778146a1439SMasami Hiramatsu 		return -EEXIST;
1779d761b08bSMasami Hiramatsu 	}
1780d761b08bSMasami Hiramatsu 
178117f88fcdSMasami Hiramatsu 	/* Try to add suffix */
178217f88fcdSMasami Hiramatsu 	for (i = 1; i < MAX_EVENT_INDEX; i++) {
1783b498ce1fSMasami Hiramatsu 		ret = e_snprintf(buf, len, "%s_%d", base, i);
1784146a1439SMasami Hiramatsu 		if (ret < 0) {
1785146a1439SMasami Hiramatsu 			pr_debug("snprintf() failed: %s\n", strerror(-ret));
1786146a1439SMasami Hiramatsu 			return ret;
1787146a1439SMasami Hiramatsu 		}
1788b498ce1fSMasami Hiramatsu 		if (!strlist__has_entry(namelist, buf))
1789b498ce1fSMasami Hiramatsu 			break;
1790b498ce1fSMasami Hiramatsu 	}
1791146a1439SMasami Hiramatsu 	if (i == MAX_EVENT_INDEX) {
1792146a1439SMasami Hiramatsu 		pr_warning("Too many events are on the same function.\n");
1793146a1439SMasami Hiramatsu 		ret = -ERANGE;
1794b498ce1fSMasami Hiramatsu 	}
1795b498ce1fSMasami Hiramatsu 
1796146a1439SMasami Hiramatsu 	return ret;
1797146a1439SMasami Hiramatsu }
1798146a1439SMasami Hiramatsu 
17990e60836bSSrikar Dronamraju static int __add_probe_trace_events(struct perf_probe_event *pev,
18000e60836bSSrikar Dronamraju 				     struct probe_trace_event *tevs,
18014235b045SMasami Hiramatsu 				     int ntevs, bool allow_suffix)
180250656eecSMasami Hiramatsu {
1803146a1439SMasami Hiramatsu 	int i, fd, ret;
18040e60836bSSrikar Dronamraju 	struct probe_trace_event *tev = NULL;
18054235b045SMasami Hiramatsu 	char buf[64];
18064235b045SMasami Hiramatsu 	const char *event, *group;
1807b498ce1fSMasami Hiramatsu 	struct strlist *namelist;
180850656eecSMasami Hiramatsu 
1809225466f1SSrikar Dronamraju 	if (pev->uprobes)
1810225466f1SSrikar Dronamraju 		fd = open_uprobe_events(true);
1811225466f1SSrikar Dronamraju 	else
1812f4d7da49SMasami Hiramatsu 		fd = open_kprobe_events(true);
1813225466f1SSrikar Dronamraju 
1814146a1439SMasami Hiramatsu 	if (fd < 0)
1815146a1439SMasami Hiramatsu 		return fd;
1816b498ce1fSMasami Hiramatsu 	/* Get current event names */
18170e60836bSSrikar Dronamraju 	namelist = get_probe_trace_event_names(fd, false);
1818146a1439SMasami Hiramatsu 	if (!namelist) {
1819146a1439SMasami Hiramatsu 		pr_debug("Failed to get current event list.\n");
1820146a1439SMasami Hiramatsu 		return -EIO;
1821146a1439SMasami Hiramatsu 	}
182250656eecSMasami Hiramatsu 
1823146a1439SMasami Hiramatsu 	ret = 0;
1824a844d1efSSrikar Dronamraju 	printf("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
182502b95dadSMasami Hiramatsu 	for (i = 0; i < ntevs; i++) {
18264235b045SMasami Hiramatsu 		tev = &tevs[i];
18274235b045SMasami Hiramatsu 		if (pev->event)
18284235b045SMasami Hiramatsu 			event = pev->event;
18294235b045SMasami Hiramatsu 		else
18304235b045SMasami Hiramatsu 			if (pev->point.function)
18314235b045SMasami Hiramatsu 				event = pev->point.function;
18324235b045SMasami Hiramatsu 			else
18334235b045SMasami Hiramatsu 				event = tev->point.symbol;
18344235b045SMasami Hiramatsu 		if (pev->group)
18354235b045SMasami Hiramatsu 			group = pev->group;
18364235b045SMasami Hiramatsu 		else
18374235b045SMasami Hiramatsu 			group = PERFPROBE_GROUP;
18384235b045SMasami Hiramatsu 
1839b498ce1fSMasami Hiramatsu 		/* Get an unused new event name */
1840146a1439SMasami Hiramatsu 		ret = get_new_event_name(buf, 64, event,
1841146a1439SMasami Hiramatsu 					 namelist, allow_suffix);
1842146a1439SMasami Hiramatsu 		if (ret < 0)
1843146a1439SMasami Hiramatsu 			break;
18444235b045SMasami Hiramatsu 		event = buf;
18454235b045SMasami Hiramatsu 
184602b95dadSMasami Hiramatsu 		tev->event = strdup(event);
184702b95dadSMasami Hiramatsu 		tev->group = strdup(group);
184802b95dadSMasami Hiramatsu 		if (tev->event == NULL || tev->group == NULL) {
184902b95dadSMasami Hiramatsu 			ret = -ENOMEM;
185002b95dadSMasami Hiramatsu 			break;
185102b95dadSMasami Hiramatsu 		}
18520e60836bSSrikar Dronamraju 		ret = write_probe_trace_event(fd, tev);
1853146a1439SMasami Hiramatsu 		if (ret < 0)
1854146a1439SMasami Hiramatsu 			break;
1855b498ce1fSMasami Hiramatsu 		/* Add added event name to namelist */
1856b498ce1fSMasami Hiramatsu 		strlist__add(namelist, event);
18574235b045SMasami Hiramatsu 
18584235b045SMasami Hiramatsu 		/* Trick here - save current event/group */
18594235b045SMasami Hiramatsu 		event = pev->event;
18604235b045SMasami Hiramatsu 		group = pev->group;
18614235b045SMasami Hiramatsu 		pev->event = tev->event;
18624235b045SMasami Hiramatsu 		pev->group = tev->group;
18634235b045SMasami Hiramatsu 		show_perf_probe_event(pev);
18644235b045SMasami Hiramatsu 		/* Trick here - restore current event/group */
18654235b045SMasami Hiramatsu 		pev->event = (char *)event;
18664235b045SMasami Hiramatsu 		pev->group = (char *)group;
18674235b045SMasami Hiramatsu 
1868d761b08bSMasami Hiramatsu 		/*
1869d761b08bSMasami Hiramatsu 		 * Probes after the first probe which comes from same
1870d761b08bSMasami Hiramatsu 		 * user input are always allowed to add suffix, because
1871d761b08bSMasami Hiramatsu 		 * there might be several addresses corresponding to
1872d761b08bSMasami Hiramatsu 		 * one code line.
1873d761b08bSMasami Hiramatsu 		 */
1874d761b08bSMasami Hiramatsu 		allow_suffix = true;
187550656eecSMasami Hiramatsu 	}
1876146a1439SMasami Hiramatsu 
1877146a1439SMasami Hiramatsu 	if (ret >= 0) {
1878a9b495b0SMasami Hiramatsu 		/* Show how to use the event. */
1879a844d1efSSrikar Dronamraju 		printf("\nYou can now use it in all perf tools, such as:\n\n");
1880146a1439SMasami Hiramatsu 		printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
1881146a1439SMasami Hiramatsu 			 tev->event);
1882146a1439SMasami Hiramatsu 	}
1883a9b495b0SMasami Hiramatsu 
1884e1d2017bSMasami Hiramatsu 	strlist__delete(namelist);
188550656eecSMasami Hiramatsu 	close(fd);
1886146a1439SMasami Hiramatsu 	return ret;
188750656eecSMasami Hiramatsu }
1888fa28244dSMasami Hiramatsu 
18890e60836bSSrikar Dronamraju static int convert_to_probe_trace_events(struct perf_probe_event *pev,
18900e60836bSSrikar Dronamraju 					  struct probe_trace_event **tevs,
18914eced234SSrikar Dronamraju 					  int max_tevs, const char *target)
1892e0faa8d3SMasami Hiramatsu {
1893e0faa8d3SMasami Hiramatsu 	struct symbol *sym;
1894e334016fSMasami Hiramatsu 	int ret = 0, i;
18950e60836bSSrikar Dronamraju 	struct probe_trace_event *tev;
18964235b045SMasami Hiramatsu 
18974b4da7f7SMasami Hiramatsu 	/* Convert perf_probe_event with debuginfo */
18984eced234SSrikar Dronamraju 	ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
1899e334016fSMasami Hiramatsu 	if (ret != 0)
1900190b57fcSMasami Hiramatsu 		return ret;	/* Found in debuginfo or got an error */
1901e0faa8d3SMasami Hiramatsu 
19024235b045SMasami Hiramatsu 	/* Allocate trace event buffer */
19030e60836bSSrikar Dronamraju 	tev = *tevs = zalloc(sizeof(struct probe_trace_event));
1904e334016fSMasami Hiramatsu 	if (tev == NULL)
1905e334016fSMasami Hiramatsu 		return -ENOMEM;
1906e0faa8d3SMasami Hiramatsu 
19074235b045SMasami Hiramatsu 	/* Copy parameters */
190802b95dadSMasami Hiramatsu 	tev->point.symbol = strdup(pev->point.function);
190902b95dadSMasami Hiramatsu 	if (tev->point.symbol == NULL) {
191002b95dadSMasami Hiramatsu 		ret = -ENOMEM;
191102b95dadSMasami Hiramatsu 		goto error;
191202b95dadSMasami Hiramatsu 	}
1913ce27a443SJovi Zhang 
19144eced234SSrikar Dronamraju 	if (target) {
19154eced234SSrikar Dronamraju 		tev->point.module = strdup(target);
1916190b57fcSMasami Hiramatsu 		if (tev->point.module == NULL) {
1917190b57fcSMasami Hiramatsu 			ret = -ENOMEM;
1918190b57fcSMasami Hiramatsu 			goto error;
1919190b57fcSMasami Hiramatsu 		}
1920ce27a443SJovi Zhang 	}
1921ce27a443SJovi Zhang 
19224235b045SMasami Hiramatsu 	tev->point.offset = pev->point.offset;
192304ddd04bSMasami Hiramatsu 	tev->point.retprobe = pev->point.retprobe;
19244235b045SMasami Hiramatsu 	tev->nargs = pev->nargs;
1925225466f1SSrikar Dronamraju 	tev->uprobes = pev->uprobes;
1926225466f1SSrikar Dronamraju 
19274235b045SMasami Hiramatsu 	if (tev->nargs) {
19280e60836bSSrikar Dronamraju 		tev->args = zalloc(sizeof(struct probe_trace_arg)
19294235b045SMasami Hiramatsu 				   * tev->nargs);
1930e334016fSMasami Hiramatsu 		if (tev->args == NULL) {
193102b95dadSMasami Hiramatsu 			ret = -ENOMEM;
193202b95dadSMasami Hiramatsu 			goto error;
1933e334016fSMasami Hiramatsu 		}
193448481938SMasami Hiramatsu 		for (i = 0; i < tev->nargs; i++) {
193502b95dadSMasami Hiramatsu 			if (pev->args[i].name) {
193602b95dadSMasami Hiramatsu 				tev->args[i].name = strdup(pev->args[i].name);
193702b95dadSMasami Hiramatsu 				if (tev->args[i].name == NULL) {
193802b95dadSMasami Hiramatsu 					ret = -ENOMEM;
193902b95dadSMasami Hiramatsu 					goto error;
194002b95dadSMasami Hiramatsu 				}
194102b95dadSMasami Hiramatsu 			}
194202b95dadSMasami Hiramatsu 			tev->args[i].value = strdup(pev->args[i].var);
194302b95dadSMasami Hiramatsu 			if (tev->args[i].value == NULL) {
194402b95dadSMasami Hiramatsu 				ret = -ENOMEM;
194502b95dadSMasami Hiramatsu 				goto error;
194602b95dadSMasami Hiramatsu 			}
194702b95dadSMasami Hiramatsu 			if (pev->args[i].type) {
194802b95dadSMasami Hiramatsu 				tev->args[i].type = strdup(pev->args[i].type);
194902b95dadSMasami Hiramatsu 				if (tev->args[i].type == NULL) {
195002b95dadSMasami Hiramatsu 					ret = -ENOMEM;
195102b95dadSMasami Hiramatsu 					goto error;
195202b95dadSMasami Hiramatsu 				}
195302b95dadSMasami Hiramatsu 			}
195448481938SMasami Hiramatsu 		}
1955e0faa8d3SMasami Hiramatsu 	}
1956e0faa8d3SMasami Hiramatsu 
1957225466f1SSrikar Dronamraju 	if (pev->uprobes)
1958225466f1SSrikar Dronamraju 		return 1;
1959225466f1SSrikar Dronamraju 
19604235b045SMasami Hiramatsu 	/* Currently just checking function name from symbol map */
1961469b9b88SMasami Hiramatsu 	sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
1962146a1439SMasami Hiramatsu 	if (!sym) {
1963146a1439SMasami Hiramatsu 		pr_warning("Kernel symbol \'%s\' not found.\n",
19644235b045SMasami Hiramatsu 			   tev->point.symbol);
196502b95dadSMasami Hiramatsu 		ret = -ENOENT;
196602b95dadSMasami Hiramatsu 		goto error;
19671c1bc922SPrashanth Nageshappa 	} else if (tev->point.offset > sym->end - sym->start) {
19681c1bc922SPrashanth Nageshappa 		pr_warning("Offset specified is greater than size of %s\n",
19691c1bc922SPrashanth Nageshappa 			   tev->point.symbol);
19701c1bc922SPrashanth Nageshappa 		ret = -ENOENT;
19711c1bc922SPrashanth Nageshappa 		goto error;
19721c1bc922SPrashanth Nageshappa 
197302b95dadSMasami Hiramatsu 	}
197402b95dadSMasami Hiramatsu 
197502b95dadSMasami Hiramatsu 	return 1;
197602b95dadSMasami Hiramatsu error:
19770e60836bSSrikar Dronamraju 	clear_probe_trace_event(tev);
1978e334016fSMasami Hiramatsu 	free(tev);
1979e334016fSMasami Hiramatsu 	*tevs = NULL;
1980e334016fSMasami Hiramatsu 	return ret;
19814235b045SMasami Hiramatsu }
19824235b045SMasami Hiramatsu 
19834235b045SMasami Hiramatsu struct __event_package {
19844235b045SMasami Hiramatsu 	struct perf_probe_event		*pev;
19850e60836bSSrikar Dronamraju 	struct probe_trace_event	*tevs;
19864235b045SMasami Hiramatsu 	int				ntevs;
19874235b045SMasami Hiramatsu };
19884235b045SMasami Hiramatsu 
1989146a1439SMasami Hiramatsu int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
19904eced234SSrikar Dronamraju 			  int max_tevs, const char *target, bool force_add)
19914235b045SMasami Hiramatsu {
1992146a1439SMasami Hiramatsu 	int i, j, ret;
19934235b045SMasami Hiramatsu 	struct __event_package *pkgs;
19944235b045SMasami Hiramatsu 
1995225466f1SSrikar Dronamraju 	ret = 0;
1996e334016fSMasami Hiramatsu 	pkgs = zalloc(sizeof(struct __event_package) * npevs);
1997225466f1SSrikar Dronamraju 
1998e334016fSMasami Hiramatsu 	if (pkgs == NULL)
1999e334016fSMasami Hiramatsu 		return -ENOMEM;
20004235b045SMasami Hiramatsu 
2001225466f1SSrikar Dronamraju 	if (!pevs->uprobes)
20024235b045SMasami Hiramatsu 		/* Init vmlinux path */
2003146a1439SMasami Hiramatsu 		ret = init_vmlinux();
2004225466f1SSrikar Dronamraju 	else
2005225466f1SSrikar Dronamraju 		ret = init_user_exec();
2006225466f1SSrikar Dronamraju 
2007449e5b24SMasami Hiramatsu 	if (ret < 0) {
2008449e5b24SMasami Hiramatsu 		free(pkgs);
2009146a1439SMasami Hiramatsu 		return ret;
2010449e5b24SMasami Hiramatsu 	}
20114235b045SMasami Hiramatsu 
20124235b045SMasami Hiramatsu 	/* Loop 1: convert all events */
20134235b045SMasami Hiramatsu 	for (i = 0; i < npevs; i++) {
20144235b045SMasami Hiramatsu 		pkgs[i].pev = &pevs[i];
20154235b045SMasami Hiramatsu 		/* Convert with or without debuginfo */
20160e60836bSSrikar Dronamraju 		ret  = convert_to_probe_trace_events(pkgs[i].pev,
2017469b9b88SMasami Hiramatsu 						     &pkgs[i].tevs,
2018469b9b88SMasami Hiramatsu 						     max_tevs,
20194eced234SSrikar Dronamraju 						     target);
2020146a1439SMasami Hiramatsu 		if (ret < 0)
2021146a1439SMasami Hiramatsu 			goto end;
2022146a1439SMasami Hiramatsu 		pkgs[i].ntevs = ret;
20234235b045SMasami Hiramatsu 	}
20244235b045SMasami Hiramatsu 
20254235b045SMasami Hiramatsu 	/* Loop 2: add all events */
20268635bf6eSArnaldo Carvalho de Melo 	for (i = 0; i < npevs; i++) {
20270e60836bSSrikar Dronamraju 		ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs,
20284235b045SMasami Hiramatsu 						pkgs[i].ntevs, force_add);
2029fbee632dSArnaldo Carvalho de Melo 		if (ret < 0)
2030fbee632dSArnaldo Carvalho de Melo 			break;
2031fbee632dSArnaldo Carvalho de Melo 	}
2032146a1439SMasami Hiramatsu end:
2033449e5b24SMasami Hiramatsu 	/* Loop 3: cleanup and free trace events  */
2034449e5b24SMasami Hiramatsu 	for (i = 0; i < npevs; i++) {
2035146a1439SMasami Hiramatsu 		for (j = 0; j < pkgs[i].ntevs; j++)
20360e60836bSSrikar Dronamraju 			clear_probe_trace_event(&pkgs[i].tevs[j]);
2037449e5b24SMasami Hiramatsu 		free(pkgs[i].tevs);
2038449e5b24SMasami Hiramatsu 	}
2039449e5b24SMasami Hiramatsu 	free(pkgs);
2040146a1439SMasami Hiramatsu 
2041146a1439SMasami Hiramatsu 	return ret;
2042e0faa8d3SMasami Hiramatsu }
2043e0faa8d3SMasami Hiramatsu 
20440e60836bSSrikar Dronamraju static int __del_trace_probe_event(int fd, struct str_node *ent)
2045bbbb521bSMasami Hiramatsu {
2046bbbb521bSMasami Hiramatsu 	char *p;
2047bbbb521bSMasami Hiramatsu 	char buf[128];
20484235b045SMasami Hiramatsu 	int ret;
2049bbbb521bSMasami Hiramatsu 
20500e60836bSSrikar Dronamraju 	/* Convert from perf-probe event to trace-probe event */
2051146a1439SMasami Hiramatsu 	ret = e_snprintf(buf, 128, "-:%s", ent->s);
2052146a1439SMasami Hiramatsu 	if (ret < 0)
2053146a1439SMasami Hiramatsu 		goto error;
2054146a1439SMasami Hiramatsu 
2055bbbb521bSMasami Hiramatsu 	p = strchr(buf + 2, ':');
2056146a1439SMasami Hiramatsu 	if (!p) {
2057146a1439SMasami Hiramatsu 		pr_debug("Internal error: %s should have ':' but not.\n",
2058146a1439SMasami Hiramatsu 			 ent->s);
2059146a1439SMasami Hiramatsu 		ret = -ENOTSUP;
2060146a1439SMasami Hiramatsu 		goto error;
2061146a1439SMasami Hiramatsu 	}
2062bbbb521bSMasami Hiramatsu 	*p = '/';
2063bbbb521bSMasami Hiramatsu 
20644235b045SMasami Hiramatsu 	pr_debug("Writing event: %s\n", buf);
20654235b045SMasami Hiramatsu 	ret = write(fd, buf, strlen(buf));
206644a56040SMasami Hiramatsu 	if (ret < 0) {
206744a56040SMasami Hiramatsu 		ret = -errno;
2068146a1439SMasami Hiramatsu 		goto error;
206944a56040SMasami Hiramatsu 	}
2070146a1439SMasami Hiramatsu 
2071a844d1efSSrikar Dronamraju 	printf("Removed event: %s\n", ent->s);
2072146a1439SMasami Hiramatsu 	return 0;
2073146a1439SMasami Hiramatsu error:
2074146a1439SMasami Hiramatsu 	pr_warning("Failed to delete event: %s\n", strerror(-ret));
2075146a1439SMasami Hiramatsu 	return ret;
2076bbbb521bSMasami Hiramatsu }
2077bbbb521bSMasami Hiramatsu 
2078225466f1SSrikar Dronamraju static int del_trace_probe_event(int fd, const char *buf,
2079225466f1SSrikar Dronamraju 						  struct strlist *namelist)
2080fa28244dSMasami Hiramatsu {
2081bbbb521bSMasami Hiramatsu 	struct str_node *ent, *n;
2082225466f1SSrikar Dronamraju 	int ret = -1;
2083fa28244dSMasami Hiramatsu 
2084bbbb521bSMasami Hiramatsu 	if (strpbrk(buf, "*?")) { /* Glob-exp */
2085bbbb521bSMasami Hiramatsu 		strlist__for_each_safe(ent, n, namelist)
2086bbbb521bSMasami Hiramatsu 			if (strglobmatch(ent->s, buf)) {
20870e60836bSSrikar Dronamraju 				ret = __del_trace_probe_event(fd, ent);
2088146a1439SMasami Hiramatsu 				if (ret < 0)
2089146a1439SMasami Hiramatsu 					break;
20903e340590SMasami Hiramatsu 				strlist__remove(namelist, ent);
2091fa28244dSMasami Hiramatsu 			}
2092bbbb521bSMasami Hiramatsu 	} else {
2093bbbb521bSMasami Hiramatsu 		ent = strlist__find(namelist, buf);
2094bbbb521bSMasami Hiramatsu 		if (ent) {
20950e60836bSSrikar Dronamraju 			ret = __del_trace_probe_event(fd, ent);
2096146a1439SMasami Hiramatsu 			if (ret >= 0)
2097bbbb521bSMasami Hiramatsu 				strlist__remove(namelist, ent);
2098bbbb521bSMasami Hiramatsu 		}
2099bbbb521bSMasami Hiramatsu 	}
2100146a1439SMasami Hiramatsu 
2101146a1439SMasami Hiramatsu 	return ret;
2102bbbb521bSMasami Hiramatsu }
2103fa28244dSMasami Hiramatsu 
2104146a1439SMasami Hiramatsu int del_perf_probe_events(struct strlist *dellist)
2105fa28244dSMasami Hiramatsu {
2106225466f1SSrikar Dronamraju 	int ret = -1, ufd = -1, kfd = -1;
2107225466f1SSrikar Dronamraju 	char buf[128];
2108fa28244dSMasami Hiramatsu 	const char *group, *event;
2109fa28244dSMasami Hiramatsu 	char *p, *str;
2110fa28244dSMasami Hiramatsu 	struct str_node *ent;
2111225466f1SSrikar Dronamraju 	struct strlist *namelist = NULL, *unamelist = NULL;
2112146a1439SMasami Hiramatsu 
2113fa28244dSMasami Hiramatsu 	/* Get current event names */
2114225466f1SSrikar Dronamraju 	kfd = open_kprobe_events(true);
2115225466f1SSrikar Dronamraju 	if (kfd < 0)
2116225466f1SSrikar Dronamraju 		return kfd;
2117225466f1SSrikar Dronamraju 
2118225466f1SSrikar Dronamraju 	namelist = get_probe_trace_event_names(kfd, true);
2119225466f1SSrikar Dronamraju 	ufd = open_uprobe_events(true);
2120225466f1SSrikar Dronamraju 
2121225466f1SSrikar Dronamraju 	if (ufd >= 0)
2122225466f1SSrikar Dronamraju 		unamelist = get_probe_trace_event_names(ufd, true);
2123225466f1SSrikar Dronamraju 
2124225466f1SSrikar Dronamraju 	if (namelist == NULL && unamelist == NULL)
2125225466f1SSrikar Dronamraju 		goto error;
2126fa28244dSMasami Hiramatsu 
2127adf365f4SMasami Hiramatsu 	strlist__for_each(ent, dellist) {
212802b95dadSMasami Hiramatsu 		str = strdup(ent->s);
212902b95dadSMasami Hiramatsu 		if (str == NULL) {
213002b95dadSMasami Hiramatsu 			ret = -ENOMEM;
2131225466f1SSrikar Dronamraju 			goto error;
213202b95dadSMasami Hiramatsu 		}
2133bbbb521bSMasami Hiramatsu 		pr_debug("Parsing: %s\n", str);
2134fa28244dSMasami Hiramatsu 		p = strchr(str, ':');
2135fa28244dSMasami Hiramatsu 		if (p) {
2136fa28244dSMasami Hiramatsu 			group = str;
2137fa28244dSMasami Hiramatsu 			*p = '\0';
2138fa28244dSMasami Hiramatsu 			event = p + 1;
2139fa28244dSMasami Hiramatsu 		} else {
2140bbbb521bSMasami Hiramatsu 			group = "*";
2141fa28244dSMasami Hiramatsu 			event = str;
2142fa28244dSMasami Hiramatsu 		}
2143225466f1SSrikar Dronamraju 
2144225466f1SSrikar Dronamraju 		ret = e_snprintf(buf, 128, "%s:%s", group, event);
2145225466f1SSrikar Dronamraju 		if (ret < 0) {
2146225466f1SSrikar Dronamraju 			pr_err("Failed to copy event.");
2147fa28244dSMasami Hiramatsu 			free(str);
2148225466f1SSrikar Dronamraju 			goto error;
2149fa28244dSMasami Hiramatsu 		}
2150225466f1SSrikar Dronamraju 
2151225466f1SSrikar Dronamraju 		pr_debug("Group: %s, Event: %s\n", group, event);
2152225466f1SSrikar Dronamraju 
2153225466f1SSrikar Dronamraju 		if (namelist)
2154225466f1SSrikar Dronamraju 			ret = del_trace_probe_event(kfd, buf, namelist);
2155225466f1SSrikar Dronamraju 
2156225466f1SSrikar Dronamraju 		if (unamelist && ret != 0)
2157225466f1SSrikar Dronamraju 			ret = del_trace_probe_event(ufd, buf, unamelist);
2158225466f1SSrikar Dronamraju 
2159225466f1SSrikar Dronamraju 		if (ret != 0)
2160225466f1SSrikar Dronamraju 			pr_info("Info: Event \"%s\" does not exist.\n", buf);
2161225466f1SSrikar Dronamraju 
2162225466f1SSrikar Dronamraju 		free(str);
2163225466f1SSrikar Dronamraju 	}
2164225466f1SSrikar Dronamraju 
2165225466f1SSrikar Dronamraju error:
2166225466f1SSrikar Dronamraju 	if (kfd >= 0) {
2167fa28244dSMasami Hiramatsu 		strlist__delete(namelist);
2168225466f1SSrikar Dronamraju 		close(kfd);
2169225466f1SSrikar Dronamraju 	}
2170225466f1SSrikar Dronamraju 
2171225466f1SSrikar Dronamraju 	if (ufd >= 0) {
2172225466f1SSrikar Dronamraju 		strlist__delete(unamelist);
2173225466f1SSrikar Dronamraju 		close(ufd);
2174225466f1SSrikar Dronamraju 	}
2175146a1439SMasami Hiramatsu 
2176146a1439SMasami Hiramatsu 	return ret;
2177fa28244dSMasami Hiramatsu }
2178225466f1SSrikar Dronamraju 
21793c42258cSMasami Hiramatsu /* TODO: don't use a global variable for filter ... */
21803c42258cSMasami Hiramatsu static struct strfilter *available_func_filter;
2181fa28244dSMasami Hiramatsu 
2182e80711caSMasami Hiramatsu /*
21833c42258cSMasami Hiramatsu  * If a symbol corresponds to a function with global binding and
21843c42258cSMasami Hiramatsu  * matches filter return 0. For all others return 1.
2185e80711caSMasami Hiramatsu  */
21863c42258cSMasami Hiramatsu static int filter_available_functions(struct map *map __unused,
2187e80711caSMasami Hiramatsu 				      struct symbol *sym)
2188e80711caSMasami Hiramatsu {
21893c42258cSMasami Hiramatsu 	if (sym->binding == STB_GLOBAL &&
21903c42258cSMasami Hiramatsu 	    strfilter__compare(available_func_filter, sym->name))
2191e80711caSMasami Hiramatsu 		return 0;
21923c42258cSMasami Hiramatsu 	return 1;
2193e80711caSMasami Hiramatsu }
2194e80711caSMasami Hiramatsu 
2195225466f1SSrikar Dronamraju static int __show_available_funcs(struct map *map)
2196e80711caSMasami Hiramatsu {
21973c42258cSMasami Hiramatsu 	if (map__load(map, filter_available_functions)) {
2198e80711caSMasami Hiramatsu 		pr_err("Failed to load map.\n");
2199e80711caSMasami Hiramatsu 		return -EINVAL;
2200e80711caSMasami Hiramatsu 	}
2201e80711caSMasami Hiramatsu 	if (!dso__sorted_by_name(map->dso, map->type))
2202e80711caSMasami Hiramatsu 		dso__sort_by_name(map->dso, map->type);
2203e80711caSMasami Hiramatsu 
2204e80711caSMasami Hiramatsu 	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
2205e80711caSMasami Hiramatsu 	return 0;
2206e80711caSMasami Hiramatsu }
2207225466f1SSrikar Dronamraju 
2208225466f1SSrikar Dronamraju static int available_kernel_funcs(const char *module)
2209225466f1SSrikar Dronamraju {
2210225466f1SSrikar Dronamraju 	struct map *map;
2211225466f1SSrikar Dronamraju 	int ret;
2212225466f1SSrikar Dronamraju 
2213225466f1SSrikar Dronamraju 	ret = init_vmlinux();
2214225466f1SSrikar Dronamraju 	if (ret < 0)
2215225466f1SSrikar Dronamraju 		return ret;
2216225466f1SSrikar Dronamraju 
2217225466f1SSrikar Dronamraju 	map = kernel_get_module_map(module);
2218225466f1SSrikar Dronamraju 	if (!map) {
2219225466f1SSrikar Dronamraju 		pr_err("Failed to find %s map.\n", (module) ? : "kernel");
2220225466f1SSrikar Dronamraju 		return -EINVAL;
2221225466f1SSrikar Dronamraju 	}
2222225466f1SSrikar Dronamraju 	return __show_available_funcs(map);
2223225466f1SSrikar Dronamraju }
2224225466f1SSrikar Dronamraju 
2225225466f1SSrikar Dronamraju static int available_user_funcs(const char *target)
2226225466f1SSrikar Dronamraju {
2227225466f1SSrikar Dronamraju 	struct map *map;
2228225466f1SSrikar Dronamraju 	int ret;
2229225466f1SSrikar Dronamraju 
2230225466f1SSrikar Dronamraju 	ret = init_user_exec();
2231225466f1SSrikar Dronamraju 	if (ret < 0)
2232225466f1SSrikar Dronamraju 		return ret;
2233225466f1SSrikar Dronamraju 
2234225466f1SSrikar Dronamraju 	map = dso__new_map(target);
2235225466f1SSrikar Dronamraju 	ret = __show_available_funcs(map);
2236225466f1SSrikar Dronamraju 	dso__delete(map->dso);
2237225466f1SSrikar Dronamraju 	map__delete(map);
2238225466f1SSrikar Dronamraju 	return ret;
2239225466f1SSrikar Dronamraju }
2240225466f1SSrikar Dronamraju 
2241225466f1SSrikar Dronamraju int show_available_funcs(const char *target, struct strfilter *_filter,
2242225466f1SSrikar Dronamraju 					bool user)
2243225466f1SSrikar Dronamraju {
2244225466f1SSrikar Dronamraju 	setup_pager();
2245225466f1SSrikar Dronamraju 	available_func_filter = _filter;
2246225466f1SSrikar Dronamraju 
2247225466f1SSrikar Dronamraju 	if (!user)
2248225466f1SSrikar Dronamraju 		return available_kernel_funcs(target);
2249225466f1SSrikar Dronamraju 
2250225466f1SSrikar Dronamraju 	return available_user_funcs(target);
2251225466f1SSrikar Dronamraju }
2252225466f1SSrikar Dronamraju 
2253225466f1SSrikar Dronamraju /*
2254225466f1SSrikar Dronamraju  * uprobe_events only accepts address:
2255225466f1SSrikar Dronamraju  * Convert function and any offset to address
2256225466f1SSrikar Dronamraju  */
2257225466f1SSrikar Dronamraju static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
2258225466f1SSrikar Dronamraju {
2259225466f1SSrikar Dronamraju 	struct perf_probe_point *pp = &pev->point;
2260225466f1SSrikar Dronamraju 	struct symbol *sym;
2261225466f1SSrikar Dronamraju 	struct map *map = NULL;
2262225466f1SSrikar Dronamraju 	char *function = NULL, *name = NULL;
2263225466f1SSrikar Dronamraju 	int ret = -EINVAL;
2264225466f1SSrikar Dronamraju 	unsigned long long vaddr = 0;
2265225466f1SSrikar Dronamraju 
2266225466f1SSrikar Dronamraju 	if (!pp->function) {
2267225466f1SSrikar Dronamraju 		pr_warning("No function specified for uprobes");
2268225466f1SSrikar Dronamraju 		goto out;
2269225466f1SSrikar Dronamraju 	}
2270225466f1SSrikar Dronamraju 
2271225466f1SSrikar Dronamraju 	function = strdup(pp->function);
2272225466f1SSrikar Dronamraju 	if (!function) {
2273225466f1SSrikar Dronamraju 		pr_warning("Failed to allocate memory by strdup.\n");
2274225466f1SSrikar Dronamraju 		ret = -ENOMEM;
2275225466f1SSrikar Dronamraju 		goto out;
2276225466f1SSrikar Dronamraju 	}
2277225466f1SSrikar Dronamraju 
2278225466f1SSrikar Dronamraju 	name = realpath(exec, NULL);
2279225466f1SSrikar Dronamraju 	if (!name) {
2280225466f1SSrikar Dronamraju 		pr_warning("Cannot find realpath for %s.\n", exec);
2281225466f1SSrikar Dronamraju 		goto out;
2282225466f1SSrikar Dronamraju 	}
2283225466f1SSrikar Dronamraju 	map = dso__new_map(name);
2284225466f1SSrikar Dronamraju 	if (!map) {
2285225466f1SSrikar Dronamraju 		pr_warning("Cannot find appropriate DSO for %s.\n", exec);
2286225466f1SSrikar Dronamraju 		goto out;
2287225466f1SSrikar Dronamraju 	}
2288225466f1SSrikar Dronamraju 	available_func_filter = strfilter__new(function, NULL);
2289225466f1SSrikar Dronamraju 	if (map__load(map, filter_available_functions)) {
2290225466f1SSrikar Dronamraju 		pr_err("Failed to load map.\n");
2291225466f1SSrikar Dronamraju 		goto out;
2292225466f1SSrikar Dronamraju 	}
2293225466f1SSrikar Dronamraju 
2294225466f1SSrikar Dronamraju 	sym = map__find_symbol_by_name(map, function, NULL);
2295225466f1SSrikar Dronamraju 	if (!sym) {
2296225466f1SSrikar Dronamraju 		pr_warning("Cannot find %s in DSO %s\n", function, exec);
2297225466f1SSrikar Dronamraju 		goto out;
2298225466f1SSrikar Dronamraju 	}
2299225466f1SSrikar Dronamraju 
2300225466f1SSrikar Dronamraju 	if (map->start > sym->start)
2301225466f1SSrikar Dronamraju 		vaddr = map->start;
2302225466f1SSrikar Dronamraju 	vaddr += sym->start + pp->offset + map->pgoff;
2303225466f1SSrikar Dronamraju 	pp->offset = 0;
2304225466f1SSrikar Dronamraju 
2305225466f1SSrikar Dronamraju 	if (!pev->event) {
2306225466f1SSrikar Dronamraju 		pev->event = function;
2307225466f1SSrikar Dronamraju 		function = NULL;
2308225466f1SSrikar Dronamraju 	}
2309225466f1SSrikar Dronamraju 	if (!pev->group) {
2310*1fb89448SDavid Ahern 		char *ptr1, *ptr2, *exec_copy;
2311225466f1SSrikar Dronamraju 
2312225466f1SSrikar Dronamraju 		pev->group = zalloc(sizeof(char *) * 64);
2313*1fb89448SDavid Ahern 		exec_copy = strdup(exec);
2314*1fb89448SDavid Ahern 		if (!exec_copy) {
2315*1fb89448SDavid Ahern 			ret = -ENOMEM;
2316*1fb89448SDavid Ahern 			pr_warning("Failed to copy exec string.\n");
2317*1fb89448SDavid Ahern 			goto out;
2318*1fb89448SDavid Ahern 		}
2319*1fb89448SDavid Ahern 
2320*1fb89448SDavid Ahern 		ptr1 = strdup(basename(exec_copy));
2321225466f1SSrikar Dronamraju 		if (ptr1) {
2322225466f1SSrikar Dronamraju 			ptr2 = strpbrk(ptr1, "-._");
2323225466f1SSrikar Dronamraju 			if (ptr2)
2324225466f1SSrikar Dronamraju 				*ptr2 = '\0';
2325225466f1SSrikar Dronamraju 			e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
2326225466f1SSrikar Dronamraju 					ptr1);
2327225466f1SSrikar Dronamraju 			free(ptr1);
2328225466f1SSrikar Dronamraju 		}
2329*1fb89448SDavid Ahern 		free(exec_copy);
2330225466f1SSrikar Dronamraju 	}
2331225466f1SSrikar Dronamraju 	free(pp->function);
2332225466f1SSrikar Dronamraju 	pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
2333225466f1SSrikar Dronamraju 	if (!pp->function) {
2334225466f1SSrikar Dronamraju 		ret = -ENOMEM;
2335225466f1SSrikar Dronamraju 		pr_warning("Failed to allocate memory by zalloc.\n");
2336225466f1SSrikar Dronamraju 		goto out;
2337225466f1SSrikar Dronamraju 	}
2338225466f1SSrikar Dronamraju 	e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
2339225466f1SSrikar Dronamraju 	ret = 0;
2340225466f1SSrikar Dronamraju 
2341225466f1SSrikar Dronamraju out:
2342225466f1SSrikar Dronamraju 	if (map) {
2343225466f1SSrikar Dronamraju 		dso__delete(map->dso);
2344225466f1SSrikar Dronamraju 		map__delete(map);
2345225466f1SSrikar Dronamraju 	}
2346225466f1SSrikar Dronamraju 	if (function)
2347225466f1SSrikar Dronamraju 		free(function);
2348225466f1SSrikar Dronamraju 	if (name)
2349225466f1SSrikar Dronamraju 		free(name);
2350225466f1SSrikar Dronamraju 	return ret;
2351225466f1SSrikar Dronamraju }
2352