xref: /linux/tools/perf/util/probe-event.c (revision 23773ca18b399051eb94f98b689cf7a9173c795b)
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"
43553873e1SBorislav Petkov #include <api/fs/debugfs.h>
44*23773ca1SSteven Rostedt (Red Hat) #include <api/fs/tracefs.h>
451d037ca1SIrina Tirdea #include "trace-event.h"	/* For __maybe_unused */
4650656eecSMasami Hiramatsu #include "probe-event.h"
474235b045SMasami Hiramatsu #include "probe-finder.h"
48225466f1SSrikar Dronamraju #include "session.h"
4950656eecSMasami Hiramatsu 
5050656eecSMasami Hiramatsu #define MAX_CMDLEN 256
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);
74981d05adSMasami Hiramatsu static void clear_probe_trace_event(struct probe_trace_event *tev);
75ee45b6c2SMasami Hiramatsu static struct machine *host_machine;
76e0faa8d3SMasami Hiramatsu 
77469b9b88SMasami Hiramatsu /* Initialize symbol maps and path of vmlinux/modules */
78ee45b6c2SMasami Hiramatsu static int init_symbol_maps(bool user_only)
79e0faa8d3SMasami Hiramatsu {
80146a1439SMasami Hiramatsu 	int ret;
81146a1439SMasami Hiramatsu 
82e0faa8d3SMasami Hiramatsu 	symbol_conf.sort_by_name = true;
830a7e6d1bSNamhyung Kim 	ret = symbol__init(NULL);
84146a1439SMasami Hiramatsu 	if (ret < 0) {
85146a1439SMasami Hiramatsu 		pr_debug("Failed to init symbol map.\n");
86146a1439SMasami Hiramatsu 		goto out;
87146a1439SMasami Hiramatsu 	}
88e0faa8d3SMasami Hiramatsu 
89ee45b6c2SMasami Hiramatsu 	if (host_machine || user_only)	/* already initialized */
90ee45b6c2SMasami Hiramatsu 		return 0;
91d28c6223SArnaldo Carvalho de Melo 
92ee45b6c2SMasami Hiramatsu 	if (symbol_conf.vmlinux_name)
93ee45b6c2SMasami Hiramatsu 		pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
94ee45b6c2SMasami Hiramatsu 
95ee45b6c2SMasami Hiramatsu 	host_machine = machine__new_host();
96ee45b6c2SMasami Hiramatsu 	if (!host_machine) {
97ee45b6c2SMasami Hiramatsu 		pr_debug("machine__new_host() failed.\n");
98ee45b6c2SMasami Hiramatsu 		symbol__exit();
99ee45b6c2SMasami Hiramatsu 		ret = -1;
100469b9b88SMasami Hiramatsu 	}
101146a1439SMasami Hiramatsu out:
102146a1439SMasami Hiramatsu 	if (ret < 0)
103146a1439SMasami Hiramatsu 		pr_warning("Failed to init vmlinux path.\n");
104146a1439SMasami Hiramatsu 	return ret;
105e0faa8d3SMasami Hiramatsu }
106e0faa8d3SMasami Hiramatsu 
107ee45b6c2SMasami Hiramatsu static void exit_symbol_maps(void)
108ee45b6c2SMasami Hiramatsu {
109ee45b6c2SMasami Hiramatsu 	if (host_machine) {
110ee45b6c2SMasami Hiramatsu 		machine__delete(host_machine);
111ee45b6c2SMasami Hiramatsu 		host_machine = NULL;
112ee45b6c2SMasami Hiramatsu 	}
113ee45b6c2SMasami Hiramatsu 	symbol__exit();
114ee45b6c2SMasami Hiramatsu }
115ee45b6c2SMasami Hiramatsu 
116469b9b88SMasami Hiramatsu static struct symbol *__find_kernel_function_by_name(const char *name,
117469b9b88SMasami Hiramatsu 						     struct map **mapp)
118e0faa8d3SMasami Hiramatsu {
119ee45b6c2SMasami Hiramatsu 	return machine__find_kernel_function_by_name(host_machine, name, mapp,
120469b9b88SMasami Hiramatsu 						     NULL);
121e0faa8d3SMasami Hiramatsu }
122469b9b88SMasami Hiramatsu 
1238f33f7deSMasami Hiramatsu static struct symbol *__find_kernel_function(u64 addr, struct map **mapp)
1248f33f7deSMasami Hiramatsu {
1258f33f7deSMasami Hiramatsu 	return machine__find_kernel_function(host_machine, addr, mapp, NULL);
1268f33f7deSMasami Hiramatsu }
1278f33f7deSMasami Hiramatsu 
1288f33f7deSMasami Hiramatsu static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void)
1298f33f7deSMasami Hiramatsu {
1308f33f7deSMasami Hiramatsu 	/* kmap->ref_reloc_sym should be set if host_machine is initialized */
1318f33f7deSMasami Hiramatsu 	struct kmap *kmap;
1328f33f7deSMasami Hiramatsu 
1338f33f7deSMasami Hiramatsu 	if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0)
1348f33f7deSMasami Hiramatsu 		return NULL;
1358f33f7deSMasami Hiramatsu 
1368f33f7deSMasami Hiramatsu 	kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]);
1378f33f7deSMasami Hiramatsu 	return kmap->ref_reloc_sym;
1388f33f7deSMasami Hiramatsu }
1398f33f7deSMasami Hiramatsu 
1408f33f7deSMasami Hiramatsu static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc)
1418f33f7deSMasami Hiramatsu {
1428f33f7deSMasami Hiramatsu 	struct ref_reloc_sym *reloc_sym;
1438f33f7deSMasami Hiramatsu 	struct symbol *sym;
1448f33f7deSMasami Hiramatsu 	struct map *map;
1458f33f7deSMasami Hiramatsu 
1468f33f7deSMasami Hiramatsu 	/* ref_reloc_sym is just a label. Need a special fix*/
1478f33f7deSMasami Hiramatsu 	reloc_sym = kernel_get_ref_reloc_sym();
1488f33f7deSMasami Hiramatsu 	if (reloc_sym && strcmp(name, reloc_sym->name) == 0)
1498f33f7deSMasami Hiramatsu 		return (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr;
1508f33f7deSMasami Hiramatsu 	else {
1518f33f7deSMasami Hiramatsu 		sym = __find_kernel_function_by_name(name, &map);
1528f33f7deSMasami Hiramatsu 		if (sym)
1538f33f7deSMasami Hiramatsu 			return map->unmap_ip(map, sym->start) -
1548f33f7deSMasami Hiramatsu 				(reloc) ? 0 : map->reloc;
1558f33f7deSMasami Hiramatsu 	}
1568f33f7deSMasami Hiramatsu 	return 0;
1578f33f7deSMasami Hiramatsu }
1588f33f7deSMasami Hiramatsu 
159e80711caSMasami Hiramatsu static struct map *kernel_get_module_map(const char *module)
160e80711caSMasami Hiramatsu {
161e80711caSMasami Hiramatsu 	struct rb_node *nd;
162ee45b6c2SMasami Hiramatsu 	struct map_groups *grp = &host_machine->kmaps;
163e80711caSMasami Hiramatsu 
16414a8fd7cSMasami Hiramatsu 	/* A file path -- this is an offline module */
16514a8fd7cSMasami Hiramatsu 	if (module && strchr(module, '/'))
166ee45b6c2SMasami Hiramatsu 		return machine__new_module(host_machine, 0, module);
16714a8fd7cSMasami Hiramatsu 
168e80711caSMasami Hiramatsu 	if (!module)
169e80711caSMasami Hiramatsu 		module = "kernel";
170e80711caSMasami Hiramatsu 
171e80711caSMasami Hiramatsu 	for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) {
172e80711caSMasami Hiramatsu 		struct map *pos = rb_entry(nd, struct map, rb_node);
173e80711caSMasami Hiramatsu 		if (strncmp(pos->dso->short_name + 1, module,
174e80711caSMasami Hiramatsu 			    pos->dso->short_name_len - 2) == 0) {
175e80711caSMasami Hiramatsu 			return pos;
176e80711caSMasami Hiramatsu 		}
177e80711caSMasami Hiramatsu 	}
178e80711caSMasami Hiramatsu 	return NULL;
179e80711caSMasami Hiramatsu }
180e80711caSMasami Hiramatsu 
181e80711caSMasami Hiramatsu static struct dso *kernel_get_module_dso(const char *module)
182469b9b88SMasami Hiramatsu {
183469b9b88SMasami Hiramatsu 	struct dso *dso;
184fd930ff9SFranck Bui-Huu 	struct map *map;
185fd930ff9SFranck Bui-Huu 	const char *vmlinux_name;
186469b9b88SMasami Hiramatsu 
187469b9b88SMasami Hiramatsu 	if (module) {
1888fa7d87fSWaiman Long 		list_for_each_entry(dso, &host_machine->kernel_dsos.head,
1898fa7d87fSWaiman Long 				    node) {
190469b9b88SMasami Hiramatsu 			if (strncmp(dso->short_name + 1, module,
191469b9b88SMasami Hiramatsu 				    dso->short_name_len - 2) == 0)
192469b9b88SMasami Hiramatsu 				goto found;
193469b9b88SMasami Hiramatsu 		}
194469b9b88SMasami Hiramatsu 		pr_debug("Failed to find module %s.\n", module);
195469b9b88SMasami Hiramatsu 		return NULL;
196fd930ff9SFranck Bui-Huu 	}
197fd930ff9SFranck Bui-Huu 
198ee45b6c2SMasami Hiramatsu 	map = host_machine->vmlinux_maps[MAP__FUNCTION];
199fd930ff9SFranck Bui-Huu 	dso = map->dso;
200fd930ff9SFranck Bui-Huu 
201fd930ff9SFranck Bui-Huu 	vmlinux_name = symbol_conf.vmlinux_name;
202fd930ff9SFranck Bui-Huu 	if (vmlinux_name) {
2035230fb7dSArnaldo Carvalho de Melo 		if (dso__load_vmlinux(dso, map, vmlinux_name, false, NULL) <= 0)
204fd930ff9SFranck Bui-Huu 			return NULL;
205469b9b88SMasami Hiramatsu 	} else {
206c3a34e06SFranck Bui-Huu 		if (dso__load_vmlinux_path(dso, map, NULL) <= 0) {
207469b9b88SMasami Hiramatsu 			pr_debug("Failed to load kernel map.\n");
208469b9b88SMasami Hiramatsu 			return NULL;
209469b9b88SMasami Hiramatsu 		}
210469b9b88SMasami Hiramatsu 	}
211469b9b88SMasami Hiramatsu found:
212e80711caSMasami Hiramatsu 	return dso;
213e80711caSMasami Hiramatsu }
214e80711caSMasami Hiramatsu 
215e80711caSMasami Hiramatsu const char *kernel_get_module_path(const char *module)
216e80711caSMasami Hiramatsu {
217e80711caSMasami Hiramatsu 	struct dso *dso = kernel_get_module_dso(module);
218e80711caSMasami Hiramatsu 	return (dso) ? dso->long_name : NULL;
219469b9b88SMasami Hiramatsu }
220469b9b88SMasami Hiramatsu 
221fb7345bbSMasami Hiramatsu static int convert_exec_to_group(const char *exec, char **result)
222fb7345bbSMasami Hiramatsu {
223fb7345bbSMasami Hiramatsu 	char *ptr1, *ptr2, *exec_copy;
224fb7345bbSMasami Hiramatsu 	char buf[64];
225fb7345bbSMasami Hiramatsu 	int ret;
226fb7345bbSMasami Hiramatsu 
227fb7345bbSMasami Hiramatsu 	exec_copy = strdup(exec);
228fb7345bbSMasami Hiramatsu 	if (!exec_copy)
229fb7345bbSMasami Hiramatsu 		return -ENOMEM;
230fb7345bbSMasami Hiramatsu 
231fb7345bbSMasami Hiramatsu 	ptr1 = basename(exec_copy);
232fb7345bbSMasami Hiramatsu 	if (!ptr1) {
233fb7345bbSMasami Hiramatsu 		ret = -EINVAL;
234fb7345bbSMasami Hiramatsu 		goto out;
235fb7345bbSMasami Hiramatsu 	}
236fb7345bbSMasami Hiramatsu 
237fb7345bbSMasami Hiramatsu 	ptr2 = strpbrk(ptr1, "-._");
238fb7345bbSMasami Hiramatsu 	if (ptr2)
239fb7345bbSMasami Hiramatsu 		*ptr2 = '\0';
240fb7345bbSMasami Hiramatsu 	ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1);
241fb7345bbSMasami Hiramatsu 	if (ret < 0)
242fb7345bbSMasami Hiramatsu 		goto out;
243fb7345bbSMasami Hiramatsu 
244fb7345bbSMasami Hiramatsu 	*result = strdup(buf);
245fb7345bbSMasami Hiramatsu 	ret = *result ? 0 : -ENOMEM;
246fb7345bbSMasami Hiramatsu 
247fb7345bbSMasami Hiramatsu out:
248fb7345bbSMasami Hiramatsu 	free(exec_copy);
249fb7345bbSMasami Hiramatsu 	return ret;
250fb7345bbSMasami Hiramatsu }
251fb7345bbSMasami Hiramatsu 
252eb948e50SMasami Hiramatsu static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
253eb948e50SMasami Hiramatsu {
254eb948e50SMasami Hiramatsu 	int i;
255eb948e50SMasami Hiramatsu 
256eb948e50SMasami Hiramatsu 	for (i = 0; i < ntevs; i++)
257eb948e50SMasami Hiramatsu 		clear_probe_trace_event(tevs + i);
258eb948e50SMasami Hiramatsu }
259eb948e50SMasami Hiramatsu 
26089fe808aSIngo Molnar #ifdef HAVE_DWARF_SUPPORT
261a15ad2f5SMasami Hiramatsu 
262ff741783SMasami Hiramatsu /* Open new debuginfo of given module */
26392561cb7SMasami Hiramatsu static struct debuginfo *open_debuginfo(const char *module, bool silent)
264469b9b88SMasami Hiramatsu {
265a15ad2f5SMasami Hiramatsu 	const char *path = module;
26692561cb7SMasami Hiramatsu 	struct debuginfo *ret;
26714a8fd7cSMasami Hiramatsu 
268a15ad2f5SMasami Hiramatsu 	if (!module || !strchr(module, '/')) {
26914a8fd7cSMasami Hiramatsu 		path = kernel_get_module_path(module);
270469b9b88SMasami Hiramatsu 		if (!path) {
27192561cb7SMasami Hiramatsu 			if (!silent)
2720e43e5d2SMasami Hiramatsu 				pr_err("Failed to find path of %s module.\n",
2730e43e5d2SMasami Hiramatsu 				       module ?: "kernel");
274ff741783SMasami Hiramatsu 			return NULL;
275469b9b88SMasami Hiramatsu 		}
27614a8fd7cSMasami Hiramatsu 	}
27792561cb7SMasami Hiramatsu 	ret = debuginfo__new(path);
27892561cb7SMasami Hiramatsu 	if (!ret && !silent) {
27992561cb7SMasami Hiramatsu 		pr_warning("The %s file has no debug information.\n", path);
28092561cb7SMasami Hiramatsu 		if (!module || !strtailcmp(path, ".ko"))
28192561cb7SMasami Hiramatsu 			pr_warning("Rebuild with CONFIG_DEBUG_INFO=y, ");
28292561cb7SMasami Hiramatsu 		else
28392561cb7SMasami Hiramatsu 			pr_warning("Rebuild with -g, ");
28492561cb7SMasami Hiramatsu 		pr_warning("or install an appropriate debuginfo package.\n");
285e0faa8d3SMasami Hiramatsu 	}
28692561cb7SMasami Hiramatsu 	return ret;
28792561cb7SMasami Hiramatsu }
28892561cb7SMasami Hiramatsu 
2894b4da7f7SMasami Hiramatsu 
29099ca4233SMasami Hiramatsu static int get_text_start_address(const char *exec, unsigned long *address)
29199ca4233SMasami Hiramatsu {
29299ca4233SMasami Hiramatsu 	Elf *elf;
29399ca4233SMasami Hiramatsu 	GElf_Ehdr ehdr;
29499ca4233SMasami Hiramatsu 	GElf_Shdr shdr;
29599ca4233SMasami Hiramatsu 	int fd, ret = -ENOENT;
29699ca4233SMasami Hiramatsu 
29799ca4233SMasami Hiramatsu 	fd = open(exec, O_RDONLY);
29899ca4233SMasami Hiramatsu 	if (fd < 0)
29999ca4233SMasami Hiramatsu 		return -errno;
30099ca4233SMasami Hiramatsu 
30199ca4233SMasami Hiramatsu 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
30299ca4233SMasami Hiramatsu 	if (elf == NULL)
30399ca4233SMasami Hiramatsu 		return -EINVAL;
30499ca4233SMasami Hiramatsu 
30599ca4233SMasami Hiramatsu 	if (gelf_getehdr(elf, &ehdr) == NULL)
30699ca4233SMasami Hiramatsu 		goto out;
30799ca4233SMasami Hiramatsu 
30899ca4233SMasami Hiramatsu 	if (!elf_section_by_name(elf, &ehdr, &shdr, ".text", NULL))
30999ca4233SMasami Hiramatsu 		goto out;
31099ca4233SMasami Hiramatsu 
31199ca4233SMasami Hiramatsu 	*address = shdr.sh_addr - shdr.sh_offset;
31299ca4233SMasami Hiramatsu 	ret = 0;
31399ca4233SMasami Hiramatsu out:
31499ca4233SMasami Hiramatsu 	elf_end(elf);
31599ca4233SMasami Hiramatsu 	return ret;
31699ca4233SMasami Hiramatsu }
31799ca4233SMasami Hiramatsu 
3185a6f6314SMasami Hiramatsu /*
3195a6f6314SMasami Hiramatsu  * Convert trace point to probe point with debuginfo
3205a6f6314SMasami Hiramatsu  */
3215a6f6314SMasami Hiramatsu static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
3225a6f6314SMasami Hiramatsu 					    struct perf_probe_point *pp,
3235a6f6314SMasami Hiramatsu 					    bool is_kprobe)
3245a6f6314SMasami Hiramatsu {
3255a6f6314SMasami Hiramatsu 	struct debuginfo *dinfo = NULL;
3265a6f6314SMasami Hiramatsu 	unsigned long stext = 0;
3275a6f6314SMasami Hiramatsu 	u64 addr = tp->address;
3285a6f6314SMasami Hiramatsu 	int ret = -ENOENT;
3295a6f6314SMasami Hiramatsu 
3305a6f6314SMasami Hiramatsu 	/* convert the address to dwarf address */
3315a6f6314SMasami Hiramatsu 	if (!is_kprobe) {
3325a6f6314SMasami Hiramatsu 		if (!addr) {
3335a6f6314SMasami Hiramatsu 			ret = -EINVAL;
3345a6f6314SMasami Hiramatsu 			goto error;
3355a6f6314SMasami Hiramatsu 		}
3365a6f6314SMasami Hiramatsu 		ret = get_text_start_address(tp->module, &stext);
3375a6f6314SMasami Hiramatsu 		if (ret < 0)
3385a6f6314SMasami Hiramatsu 			goto error;
3395a6f6314SMasami Hiramatsu 		addr += stext;
3405a6f6314SMasami Hiramatsu 	} else {
3415a6f6314SMasami Hiramatsu 		addr = kernel_get_symbol_address_by_name(tp->symbol, false);
3425a6f6314SMasami Hiramatsu 		if (addr == 0)
3435a6f6314SMasami Hiramatsu 			goto error;
3445a6f6314SMasami Hiramatsu 		addr += tp->offset;
3455a6f6314SMasami Hiramatsu 	}
3465a6f6314SMasami Hiramatsu 
3475a6f6314SMasami Hiramatsu 	pr_debug("try to find information at %" PRIx64 " in %s\n", addr,
3485a6f6314SMasami Hiramatsu 		 tp->module ? : "kernel");
3495a6f6314SMasami Hiramatsu 
35092561cb7SMasami Hiramatsu 	dinfo = open_debuginfo(tp->module, verbose == 0);
3515a6f6314SMasami Hiramatsu 	if (dinfo) {
3525a6f6314SMasami Hiramatsu 		ret = debuginfo__find_probe_point(dinfo,
3535a6f6314SMasami Hiramatsu 						 (unsigned long)addr, pp);
3545a6f6314SMasami Hiramatsu 		debuginfo__delete(dinfo);
35592561cb7SMasami Hiramatsu 	} else
3565a6f6314SMasami Hiramatsu 		ret = -ENOENT;
3575a6f6314SMasami Hiramatsu 
3585a6f6314SMasami Hiramatsu 	if (ret > 0) {
3595a6f6314SMasami Hiramatsu 		pp->retprobe = tp->retprobe;
3605a6f6314SMasami Hiramatsu 		return 0;
3615a6f6314SMasami Hiramatsu 	}
3625a6f6314SMasami Hiramatsu error:
3635a6f6314SMasami Hiramatsu 	pr_debug("Failed to find corresponding probes from debuginfo.\n");
3645a6f6314SMasami Hiramatsu 	return ret ? : -ENOENT;
3655a6f6314SMasami Hiramatsu }
3665a6f6314SMasami Hiramatsu 
367fb7345bbSMasami Hiramatsu static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
368fb7345bbSMasami Hiramatsu 					  int ntevs, const char *exec)
369fb7345bbSMasami Hiramatsu {
370fb7345bbSMasami Hiramatsu 	int i, ret = 0;
371eb948e50SMasami Hiramatsu 	unsigned long stext = 0;
372fb7345bbSMasami Hiramatsu 
373fb7345bbSMasami Hiramatsu 	if (!exec)
374fb7345bbSMasami Hiramatsu 		return 0;
375fb7345bbSMasami Hiramatsu 
376fb7345bbSMasami Hiramatsu 	ret = get_text_start_address(exec, &stext);
377fb7345bbSMasami Hiramatsu 	if (ret < 0)
378fb7345bbSMasami Hiramatsu 		return ret;
379fb7345bbSMasami Hiramatsu 
380fb7345bbSMasami Hiramatsu 	for (i = 0; i < ntevs && ret >= 0; i++) {
381981a2379SMasami Hiramatsu 		/* point.address is the addres of point.symbol + point.offset */
382eb948e50SMasami Hiramatsu 		tevs[i].point.address -= stext;
383fb7345bbSMasami Hiramatsu 		tevs[i].point.module = strdup(exec);
384eb948e50SMasami Hiramatsu 		if (!tevs[i].point.module) {
385fb7345bbSMasami Hiramatsu 			ret = -ENOMEM;
386fb7345bbSMasami Hiramatsu 			break;
387fb7345bbSMasami Hiramatsu 		}
388fb7345bbSMasami Hiramatsu 		tevs[i].uprobes = true;
389fb7345bbSMasami Hiramatsu 	}
390fb7345bbSMasami Hiramatsu 
391fb7345bbSMasami Hiramatsu 	return ret;
392fb7345bbSMasami Hiramatsu }
393fb7345bbSMasami Hiramatsu 
394190b57fcSMasami Hiramatsu static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
395190b57fcSMasami Hiramatsu 					    int ntevs, const char *module)
396190b57fcSMasami Hiramatsu {
39714a8fd7cSMasami Hiramatsu 	int i, ret = 0;
39814a8fd7cSMasami Hiramatsu 	char *tmp;
39914a8fd7cSMasami Hiramatsu 
40014a8fd7cSMasami Hiramatsu 	if (!module)
40114a8fd7cSMasami Hiramatsu 		return 0;
40214a8fd7cSMasami Hiramatsu 
40314a8fd7cSMasami Hiramatsu 	tmp = strrchr(module, '/');
40414a8fd7cSMasami Hiramatsu 	if (tmp) {
40514a8fd7cSMasami Hiramatsu 		/* This is a module path -- get the module name */
40614a8fd7cSMasami Hiramatsu 		module = strdup(tmp + 1);
40714a8fd7cSMasami Hiramatsu 		if (!module)
40814a8fd7cSMasami Hiramatsu 			return -ENOMEM;
40914a8fd7cSMasami Hiramatsu 		tmp = strchr(module, '.');
41014a8fd7cSMasami Hiramatsu 		if (tmp)
41114a8fd7cSMasami Hiramatsu 			*tmp = '\0';
41214a8fd7cSMasami Hiramatsu 		tmp = (char *)module;	/* For free() */
41314a8fd7cSMasami Hiramatsu 	}
41414a8fd7cSMasami Hiramatsu 
415190b57fcSMasami Hiramatsu 	for (i = 0; i < ntevs; i++) {
416190b57fcSMasami Hiramatsu 		tevs[i].point.module = strdup(module);
41714a8fd7cSMasami Hiramatsu 		if (!tevs[i].point.module) {
41814a8fd7cSMasami Hiramatsu 			ret = -ENOMEM;
41914a8fd7cSMasami Hiramatsu 			break;
420190b57fcSMasami Hiramatsu 		}
42114a8fd7cSMasami Hiramatsu 	}
42214a8fd7cSMasami Hiramatsu 
42314a8fd7cSMasami Hiramatsu 	free(tmp);
42414a8fd7cSMasami Hiramatsu 	return ret;
425190b57fcSMasami Hiramatsu }
426190b57fcSMasami Hiramatsu 
427dfef99cdSMasami Hiramatsu /* Post processing the probe events */
428dfef99cdSMasami Hiramatsu static int post_process_probe_trace_events(struct probe_trace_event *tevs,
429dfef99cdSMasami Hiramatsu 					   int ntevs, const char *module,
430dfef99cdSMasami Hiramatsu 					   bool uprobe)
431dfef99cdSMasami Hiramatsu {
432dfef99cdSMasami Hiramatsu 	struct ref_reloc_sym *reloc_sym;
433dfef99cdSMasami Hiramatsu 	char *tmp;
434dfef99cdSMasami Hiramatsu 	int i;
435dfef99cdSMasami Hiramatsu 
436dfef99cdSMasami Hiramatsu 	if (uprobe)
437dfef99cdSMasami Hiramatsu 		return add_exec_to_probe_trace_events(tevs, ntevs, module);
438dfef99cdSMasami Hiramatsu 
439dfef99cdSMasami Hiramatsu 	/* Note that currently ref_reloc_sym based probe is not for drivers */
440dfef99cdSMasami Hiramatsu 	if (module)
441dfef99cdSMasami Hiramatsu 		return add_module_to_probe_trace_events(tevs, ntevs, module);
442dfef99cdSMasami Hiramatsu 
4438f33f7deSMasami Hiramatsu 	reloc_sym = kernel_get_ref_reloc_sym();
444dfef99cdSMasami Hiramatsu 	if (!reloc_sym) {
445dfef99cdSMasami Hiramatsu 		pr_warning("Relocated base symbol is not found!\n");
446dfef99cdSMasami Hiramatsu 		return -EINVAL;
447dfef99cdSMasami Hiramatsu 	}
448dfef99cdSMasami Hiramatsu 
449dfef99cdSMasami Hiramatsu 	for (i = 0; i < ntevs; i++) {
45025dd9171SNamhyung Kim 		if (tevs[i].point.address && !tevs[i].point.retprobe) {
451dfef99cdSMasami Hiramatsu 			tmp = strdup(reloc_sym->name);
452dfef99cdSMasami Hiramatsu 			if (!tmp)
453dfef99cdSMasami Hiramatsu 				return -ENOMEM;
454dfef99cdSMasami Hiramatsu 			free(tevs[i].point.symbol);
455dfef99cdSMasami Hiramatsu 			tevs[i].point.symbol = tmp;
456dfef99cdSMasami Hiramatsu 			tevs[i].point.offset = tevs[i].point.address -
457dfef99cdSMasami Hiramatsu 					       reloc_sym->unrelocated_addr;
458dfef99cdSMasami Hiramatsu 		}
459dfef99cdSMasami Hiramatsu 	}
460dfef99cdSMasami Hiramatsu 	return 0;
461dfef99cdSMasami Hiramatsu }
462dfef99cdSMasami Hiramatsu 
4634b4da7f7SMasami Hiramatsu /* Try to find perf_probe_event with debuginfo */
4640e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
4650e60836bSSrikar Dronamraju 					  struct probe_trace_event **tevs,
4664eced234SSrikar Dronamraju 					  int max_tevs, const char *target)
4674b4da7f7SMasami Hiramatsu {
4684b4da7f7SMasami Hiramatsu 	bool need_dwarf = perf_probe_event_need_dwarf(pev);
469225466f1SSrikar Dronamraju 	struct debuginfo *dinfo;
470190b57fcSMasami Hiramatsu 	int ntevs, ret = 0;
4714b4da7f7SMasami Hiramatsu 
47292561cb7SMasami Hiramatsu 	dinfo = open_debuginfo(target, !need_dwarf);
473225466f1SSrikar Dronamraju 
474ff741783SMasami Hiramatsu 	if (!dinfo) {
47592561cb7SMasami Hiramatsu 		if (need_dwarf)
476ff741783SMasami Hiramatsu 			return -ENOENT;
477ff741783SMasami Hiramatsu 		pr_debug("Could not open debuginfo. Try to use symbols.\n");
4784b4da7f7SMasami Hiramatsu 		return 0;
4794b4da7f7SMasami Hiramatsu 	}
4804b4da7f7SMasami Hiramatsu 
481dfef99cdSMasami Hiramatsu 	pr_debug("Try to find probe point from debuginfo.\n");
482ff741783SMasami Hiramatsu 	/* Searching trace events corresponding to a probe event */
483ff741783SMasami Hiramatsu 	ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs);
484ff741783SMasami Hiramatsu 
485ff741783SMasami Hiramatsu 	debuginfo__delete(dinfo);
4864b4da7f7SMasami Hiramatsu 
487146a1439SMasami Hiramatsu 	if (ntevs > 0) {	/* Succeeded to find trace events */
488dfef99cdSMasami Hiramatsu 		pr_debug("Found %d probe_trace_events.\n", ntevs);
489dfef99cdSMasami Hiramatsu 		ret = post_process_probe_trace_events(*tevs, ntevs,
490dfef99cdSMasami Hiramatsu 							target, pev->uprobes);
491981d05adSMasami Hiramatsu 		if (ret < 0) {
492981d05adSMasami Hiramatsu 			clear_probe_trace_events(*tevs, ntevs);
493981d05adSMasami Hiramatsu 			zfree(tevs);
494981d05adSMasami Hiramatsu 		}
495190b57fcSMasami Hiramatsu 		return ret < 0 ? ret : ntevs;
496146a1439SMasami Hiramatsu 	}
4974b4da7f7SMasami Hiramatsu 
498146a1439SMasami Hiramatsu 	if (ntevs == 0)	{	/* No error but failed to find probe point. */
499906451b9SMasami Hiramatsu 		pr_warning("Probe point '%s' not found in debuginfo.\n",
5004b4da7f7SMasami Hiramatsu 			   synthesize_perf_probe_point(&pev->point));
501906451b9SMasami Hiramatsu 		if (need_dwarf)
502146a1439SMasami Hiramatsu 			return -ENOENT;
503906451b9SMasami Hiramatsu 		return 0;
504146a1439SMasami Hiramatsu 	}
505146a1439SMasami Hiramatsu 	/* Error path : ntevs < 0 */
50615eca306SMasami Hiramatsu 	pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
50715eca306SMasami Hiramatsu 	if (ntevs == -EBADF) {
50815eca306SMasami Hiramatsu 		pr_warning("Warning: No dwarf info found in the vmlinux - "
50915eca306SMasami Hiramatsu 			"please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
51015eca306SMasami Hiramatsu 		if (!need_dwarf) {
5110e43e5d2SMasami Hiramatsu 			pr_debug("Trying to use symbols.\n");
5124b4da7f7SMasami Hiramatsu 			return 0;
5134b4da7f7SMasami Hiramatsu 		}
51415eca306SMasami Hiramatsu 	}
51515eca306SMasami Hiramatsu 	return ntevs;
51615eca306SMasami Hiramatsu }
5174b4da7f7SMasami Hiramatsu 
5187cf0b79eSMasami Hiramatsu /*
5197cf0b79eSMasami Hiramatsu  * Find a src file from a DWARF tag path. Prepend optional source path prefix
5207cf0b79eSMasami Hiramatsu  * and chop off leading directories that do not exist. Result is passed back as
5217cf0b79eSMasami Hiramatsu  * a newly allocated path on success.
5227cf0b79eSMasami Hiramatsu  * Return 0 if file was found and readable, -errno otherwise.
5237cf0b79eSMasami Hiramatsu  */
5246a330a3cSMasami Hiramatsu static int get_real_path(const char *raw_path, const char *comp_dir,
5256a330a3cSMasami Hiramatsu 			 char **new_path)
5267cf0b79eSMasami Hiramatsu {
5276a330a3cSMasami Hiramatsu 	const char *prefix = symbol_conf.source_prefix;
5286a330a3cSMasami Hiramatsu 
5296a330a3cSMasami Hiramatsu 	if (!prefix) {
5306a330a3cSMasami Hiramatsu 		if (raw_path[0] != '/' && comp_dir)
5316a330a3cSMasami Hiramatsu 			/* If not an absolute path, try to use comp_dir */
5326a330a3cSMasami Hiramatsu 			prefix = comp_dir;
5336a330a3cSMasami Hiramatsu 		else {
5347cf0b79eSMasami Hiramatsu 			if (access(raw_path, R_OK) == 0) {
5357cf0b79eSMasami Hiramatsu 				*new_path = strdup(raw_path);
5367cf0b79eSMasami Hiramatsu 				return 0;
5377cf0b79eSMasami Hiramatsu 			} else
5387cf0b79eSMasami Hiramatsu 				return -errno;
5397cf0b79eSMasami Hiramatsu 		}
5406a330a3cSMasami Hiramatsu 	}
5417cf0b79eSMasami Hiramatsu 
5426a330a3cSMasami Hiramatsu 	*new_path = malloc((strlen(prefix) + strlen(raw_path) + 2));
5437cf0b79eSMasami Hiramatsu 	if (!*new_path)
5447cf0b79eSMasami Hiramatsu 		return -ENOMEM;
5457cf0b79eSMasami Hiramatsu 
5467cf0b79eSMasami Hiramatsu 	for (;;) {
5476a330a3cSMasami Hiramatsu 		sprintf(*new_path, "%s/%s", prefix, raw_path);
5487cf0b79eSMasami Hiramatsu 
5497cf0b79eSMasami Hiramatsu 		if (access(*new_path, R_OK) == 0)
5507cf0b79eSMasami Hiramatsu 			return 0;
5517cf0b79eSMasami Hiramatsu 
5526a330a3cSMasami Hiramatsu 		if (!symbol_conf.source_prefix)
5536a330a3cSMasami Hiramatsu 			/* In case of searching comp_dir, don't retry */
5546a330a3cSMasami Hiramatsu 			return -errno;
5556a330a3cSMasami Hiramatsu 
5567cf0b79eSMasami Hiramatsu 		switch (errno) {
5577cf0b79eSMasami Hiramatsu 		case ENAMETOOLONG:
5587cf0b79eSMasami Hiramatsu 		case ENOENT:
5597cf0b79eSMasami Hiramatsu 		case EROFS:
5607cf0b79eSMasami Hiramatsu 		case EFAULT:
5617cf0b79eSMasami Hiramatsu 			raw_path = strchr(++raw_path, '/');
5627cf0b79eSMasami Hiramatsu 			if (!raw_path) {
56304662523SArnaldo Carvalho de Melo 				zfree(new_path);
5647cf0b79eSMasami Hiramatsu 				return -ENOENT;
5657cf0b79eSMasami Hiramatsu 			}
5667cf0b79eSMasami Hiramatsu 			continue;
5677cf0b79eSMasami Hiramatsu 
5687cf0b79eSMasami Hiramatsu 		default:
56904662523SArnaldo Carvalho de Melo 			zfree(new_path);
5707cf0b79eSMasami Hiramatsu 			return -errno;
5717cf0b79eSMasami Hiramatsu 		}
5727cf0b79eSMasami Hiramatsu 	}
5737cf0b79eSMasami Hiramatsu }
5747cf0b79eSMasami Hiramatsu 
5754b4da7f7SMasami Hiramatsu #define LINEBUF_SIZE 256
5764b4da7f7SMasami Hiramatsu #define NR_ADDITIONAL_LINES 2
5774b4da7f7SMasami Hiramatsu 
578fde52dbdSFranck Bui-Huu static int __show_one_line(FILE *fp, int l, bool skip, bool show_num)
5794b4da7f7SMasami Hiramatsu {
5805f03cba4SMasami Hiramatsu 	char buf[LINEBUF_SIZE], sbuf[STRERR_BUFSIZE];
581befe3414SFranck Bui-Huu 	const char *color = show_num ? "" : PERF_COLOR_BLUE;
582befe3414SFranck Bui-Huu 	const char *prefix = NULL;
5834b4da7f7SMasami Hiramatsu 
584befe3414SFranck Bui-Huu 	do {
5854b4da7f7SMasami Hiramatsu 		if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
5864b4da7f7SMasami Hiramatsu 			goto error;
587befe3414SFranck Bui-Huu 		if (skip)
588befe3414SFranck Bui-Huu 			continue;
589befe3414SFranck Bui-Huu 		if (!prefix) {
590befe3414SFranck Bui-Huu 			prefix = show_num ? "%7d  " : "         ";
591befe3414SFranck Bui-Huu 			color_fprintf(stdout, color, prefix, l);
5924b4da7f7SMasami Hiramatsu 		}
593befe3414SFranck Bui-Huu 		color_fprintf(stdout, color, "%s", buf);
5944b4da7f7SMasami Hiramatsu 
595befe3414SFranck Bui-Huu 	} while (strchr(buf, '\n') == NULL);
596146a1439SMasami Hiramatsu 
597fde52dbdSFranck Bui-Huu 	return 1;
5984b4da7f7SMasami Hiramatsu error:
599fde52dbdSFranck Bui-Huu 	if (ferror(fp)) {
6005f03cba4SMasami Hiramatsu 		pr_warning("File read error: %s\n",
6015f03cba4SMasami Hiramatsu 			   strerror_r(errno, sbuf, sizeof(sbuf)));
602146a1439SMasami Hiramatsu 		return -1;
6034b4da7f7SMasami Hiramatsu 	}
604fde52dbdSFranck Bui-Huu 	return 0;
605fde52dbdSFranck Bui-Huu }
606fde52dbdSFranck Bui-Huu 
607fde52dbdSFranck Bui-Huu static int _show_one_line(FILE *fp, int l, bool skip, bool show_num)
608fde52dbdSFranck Bui-Huu {
609fde52dbdSFranck Bui-Huu 	int rv = __show_one_line(fp, l, skip, show_num);
610fde52dbdSFranck Bui-Huu 	if (rv == 0) {
611fde52dbdSFranck Bui-Huu 		pr_warning("Source file is shorter than expected.\n");
612fde52dbdSFranck Bui-Huu 		rv = -1;
613fde52dbdSFranck Bui-Huu 	}
614fde52dbdSFranck Bui-Huu 	return rv;
615fde52dbdSFranck Bui-Huu }
616fde52dbdSFranck Bui-Huu 
617fde52dbdSFranck Bui-Huu #define show_one_line_with_num(f,l)	_show_one_line(f,l,false,true)
618fde52dbdSFranck Bui-Huu #define show_one_line(f,l)		_show_one_line(f,l,false,false)
619fde52dbdSFranck Bui-Huu #define skip_one_line(f,l)		_show_one_line(f,l,true,false)
620fde52dbdSFranck Bui-Huu #define show_one_line_or_eof(f,l)	__show_one_line(f,l,false,false)
6214b4da7f7SMasami Hiramatsu 
6224b4da7f7SMasami Hiramatsu /*
6234b4da7f7SMasami Hiramatsu  * Show line-range always requires debuginfo to find source file and
6244b4da7f7SMasami Hiramatsu  * line number.
6254b4da7f7SMasami Hiramatsu  */
626ee45b6c2SMasami Hiramatsu static int __show_line_range(struct line_range *lr, const char *module)
6274b4da7f7SMasami Hiramatsu {
628d3b63d7aSMasami Hiramatsu 	int l = 1;
6295a62257aSMasami Hiramatsu 	struct int_node *ln;
630ff741783SMasami Hiramatsu 	struct debuginfo *dinfo;
6314b4da7f7SMasami Hiramatsu 	FILE *fp;
632ff741783SMasami Hiramatsu 	int ret;
6337cf0b79eSMasami Hiramatsu 	char *tmp;
6345f03cba4SMasami Hiramatsu 	char sbuf[STRERR_BUFSIZE];
6354b4da7f7SMasami Hiramatsu 
6364b4da7f7SMasami Hiramatsu 	/* Search a line range */
63792561cb7SMasami Hiramatsu 	dinfo = open_debuginfo(module, false);
63892561cb7SMasami Hiramatsu 	if (!dinfo)
639ff741783SMasami Hiramatsu 		return -ENOENT;
640146a1439SMasami Hiramatsu 
641ff741783SMasami Hiramatsu 	ret = debuginfo__find_line_range(dinfo, lr);
642ff741783SMasami Hiramatsu 	debuginfo__delete(dinfo);
6435ee05b88SMasami Hiramatsu 	if (ret == 0 || ret == -ENOENT) {
644146a1439SMasami Hiramatsu 		pr_warning("Specified source line is not found.\n");
645146a1439SMasami Hiramatsu 		return -ENOENT;
646146a1439SMasami Hiramatsu 	} else if (ret < 0) {
6475ee05b88SMasami Hiramatsu 		pr_warning("Debuginfo analysis failed.\n");
648146a1439SMasami Hiramatsu 		return ret;
649146a1439SMasami Hiramatsu 	}
6504b4da7f7SMasami Hiramatsu 
6517cf0b79eSMasami Hiramatsu 	/* Convert source file path */
6527cf0b79eSMasami Hiramatsu 	tmp = lr->path;
6536a330a3cSMasami Hiramatsu 	ret = get_real_path(tmp, lr->comp_dir, &lr->path);
6547cf0b79eSMasami Hiramatsu 	free(tmp);	/* Free old path */
6557cf0b79eSMasami Hiramatsu 	if (ret < 0) {
6565ee05b88SMasami Hiramatsu 		pr_warning("Failed to find source file path.\n");
6577cf0b79eSMasami Hiramatsu 		return ret;
6587cf0b79eSMasami Hiramatsu 	}
6597cf0b79eSMasami Hiramatsu 
6604b4da7f7SMasami Hiramatsu 	setup_pager();
6614b4da7f7SMasami Hiramatsu 
6624b4da7f7SMasami Hiramatsu 	if (lr->function)
6638737ebdeSMasami Hiramatsu 		fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path,
6644b4da7f7SMasami Hiramatsu 			lr->start - lr->offset);
6654b4da7f7SMasami Hiramatsu 	else
66662c15fc4SFranck Bui-Huu 		fprintf(stdout, "<%s:%d>\n", lr->path, lr->start);
6674b4da7f7SMasami Hiramatsu 
6684b4da7f7SMasami Hiramatsu 	fp = fopen(lr->path, "r");
669146a1439SMasami Hiramatsu 	if (fp == NULL) {
670146a1439SMasami Hiramatsu 		pr_warning("Failed to open %s: %s\n", lr->path,
6715f03cba4SMasami Hiramatsu 			   strerror_r(errno, sbuf, sizeof(sbuf)));
672146a1439SMasami Hiramatsu 		return -errno;
673146a1439SMasami Hiramatsu 	}
6744b4da7f7SMasami Hiramatsu 	/* Skip to starting line number */
67544b81e92SFranck Bui-Huu 	while (l < lr->start) {
676fde52dbdSFranck Bui-Huu 		ret = skip_one_line(fp, l++);
677146a1439SMasami Hiramatsu 		if (ret < 0)
678146a1439SMasami Hiramatsu 			goto end;
67944b81e92SFranck Bui-Huu 	}
6804b4da7f7SMasami Hiramatsu 
6815a62257aSMasami Hiramatsu 	intlist__for_each(ln, lr->line_list) {
6825a62257aSMasami Hiramatsu 		for (; ln->i > l; l++) {
683fde52dbdSFranck Bui-Huu 			ret = show_one_line(fp, l - lr->offset);
68444b81e92SFranck Bui-Huu 			if (ret < 0)
68544b81e92SFranck Bui-Huu 				goto end;
68644b81e92SFranck Bui-Huu 		}
687fde52dbdSFranck Bui-Huu 		ret = show_one_line_with_num(fp, l++ - lr->offset);
688146a1439SMasami Hiramatsu 		if (ret < 0)
689146a1439SMasami Hiramatsu 			goto end;
6904b4da7f7SMasami Hiramatsu 	}
6914b4da7f7SMasami Hiramatsu 
6924b4da7f7SMasami Hiramatsu 	if (lr->end == INT_MAX)
6934b4da7f7SMasami Hiramatsu 		lr->end = l + NR_ADDITIONAL_LINES;
694fde52dbdSFranck Bui-Huu 	while (l <= lr->end) {
695fde52dbdSFranck Bui-Huu 		ret = show_one_line_or_eof(fp, l++ - lr->offset);
696fde52dbdSFranck Bui-Huu 		if (ret <= 0)
69744b81e92SFranck Bui-Huu 			break;
69844b81e92SFranck Bui-Huu 	}
699146a1439SMasami Hiramatsu end:
7004b4da7f7SMasami Hiramatsu 	fclose(fp);
701146a1439SMasami Hiramatsu 	return ret;
7024b4da7f7SMasami Hiramatsu }
7034b4da7f7SMasami Hiramatsu 
7042b394bc4SMasami Hiramatsu int show_line_range(struct line_range *lr, const char *module, bool user)
705ee45b6c2SMasami Hiramatsu {
706ee45b6c2SMasami Hiramatsu 	int ret;
707ee45b6c2SMasami Hiramatsu 
7082b394bc4SMasami Hiramatsu 	ret = init_symbol_maps(user);
709ee45b6c2SMasami Hiramatsu 	if (ret < 0)
710ee45b6c2SMasami Hiramatsu 		return ret;
711ee45b6c2SMasami Hiramatsu 	ret = __show_line_range(lr, module);
712ee45b6c2SMasami Hiramatsu 	exit_symbol_maps();
713ee45b6c2SMasami Hiramatsu 
714ee45b6c2SMasami Hiramatsu 	return ret;
715ee45b6c2SMasami Hiramatsu }
716ee45b6c2SMasami Hiramatsu 
717ff741783SMasami Hiramatsu static int show_available_vars_at(struct debuginfo *dinfo,
718ff741783SMasami Hiramatsu 				  struct perf_probe_event *pev,
719bd09d7b5SMasami Hiramatsu 				  int max_vls, struct strfilter *_filter,
720bd09d7b5SMasami Hiramatsu 				  bool externs)
721cf6eb489SMasami Hiramatsu {
722cf6eb489SMasami Hiramatsu 	char *buf;
723bd09d7b5SMasami Hiramatsu 	int ret, i, nvars;
724cf6eb489SMasami Hiramatsu 	struct str_node *node;
725cf6eb489SMasami Hiramatsu 	struct variable_list *vls = NULL, *vl;
726bd09d7b5SMasami Hiramatsu 	const char *var;
727cf6eb489SMasami Hiramatsu 
728cf6eb489SMasami Hiramatsu 	buf = synthesize_perf_probe_point(&pev->point);
729cf6eb489SMasami Hiramatsu 	if (!buf)
730cf6eb489SMasami Hiramatsu 		return -EINVAL;
731cf6eb489SMasami Hiramatsu 	pr_debug("Searching variables at %s\n", buf);
732cf6eb489SMasami Hiramatsu 
733ff741783SMasami Hiramatsu 	ret = debuginfo__find_available_vars_at(dinfo, pev, &vls,
734ff741783SMasami Hiramatsu 						max_vls, externs);
735bd09d7b5SMasami Hiramatsu 	if (ret <= 0) {
73669e96eaaSMasami Hiramatsu 		if (ret == 0 || ret == -ENOENT) {
73769e96eaaSMasami Hiramatsu 			pr_err("Failed to find the address of %s\n", buf);
73869e96eaaSMasami Hiramatsu 			ret = -ENOENT;
73969e96eaaSMasami Hiramatsu 		} else
74069e96eaaSMasami Hiramatsu 			pr_warning("Debuginfo analysis failed.\n");
741bd09d7b5SMasami Hiramatsu 		goto end;
742bd09d7b5SMasami Hiramatsu 	}
74369e96eaaSMasami Hiramatsu 
744bd09d7b5SMasami Hiramatsu 	/* Some variables are found */
745cf6eb489SMasami Hiramatsu 	fprintf(stdout, "Available variables at %s\n", buf);
746cf6eb489SMasami Hiramatsu 	for (i = 0; i < ret; i++) {
747cf6eb489SMasami Hiramatsu 		vl = &vls[i];
748cf6eb489SMasami Hiramatsu 		/*
749cf6eb489SMasami Hiramatsu 		 * A probe point might be converted to
750cf6eb489SMasami Hiramatsu 		 * several trace points.
751cf6eb489SMasami Hiramatsu 		 */
752cf6eb489SMasami Hiramatsu 		fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
753cf6eb489SMasami Hiramatsu 			vl->point.offset);
75474cf249dSArnaldo Carvalho de Melo 		zfree(&vl->point.symbol);
755bd09d7b5SMasami Hiramatsu 		nvars = 0;
756cf6eb489SMasami Hiramatsu 		if (vl->vars) {
757bd09d7b5SMasami Hiramatsu 			strlist__for_each(node, vl->vars) {
758bd09d7b5SMasami Hiramatsu 				var = strchr(node->s, '\t') + 1;
759bd09d7b5SMasami Hiramatsu 				if (strfilter__compare(_filter, var)) {
760cf6eb489SMasami Hiramatsu 					fprintf(stdout, "\t\t%s\n", node->s);
761bd09d7b5SMasami Hiramatsu 					nvars++;
762bd09d7b5SMasami Hiramatsu 				}
763bd09d7b5SMasami Hiramatsu 			}
764cf6eb489SMasami Hiramatsu 			strlist__delete(vl->vars);
765bd09d7b5SMasami Hiramatsu 		}
766bd09d7b5SMasami Hiramatsu 		if (nvars == 0)
767bd09d7b5SMasami Hiramatsu 			fprintf(stdout, "\t\t(No matched variables)\n");
768cf6eb489SMasami Hiramatsu 	}
769cf6eb489SMasami Hiramatsu 	free(vls);
770bd09d7b5SMasami Hiramatsu end:
771cf6eb489SMasami Hiramatsu 	free(buf);
772cf6eb489SMasami Hiramatsu 	return ret;
773cf6eb489SMasami Hiramatsu }
774cf6eb489SMasami Hiramatsu 
775cf6eb489SMasami Hiramatsu /* Show available variables on given probe point */
776cf6eb489SMasami Hiramatsu int show_available_vars(struct perf_probe_event *pevs, int npevs,
777bd09d7b5SMasami Hiramatsu 			int max_vls, const char *module,
778bd09d7b5SMasami Hiramatsu 			struct strfilter *_filter, bool externs)
779cf6eb489SMasami Hiramatsu {
780ff741783SMasami Hiramatsu 	int i, ret = 0;
781ff741783SMasami Hiramatsu 	struct debuginfo *dinfo;
782cf6eb489SMasami Hiramatsu 
7832b394bc4SMasami Hiramatsu 	ret = init_symbol_maps(pevs->uprobes);
784cf6eb489SMasami Hiramatsu 	if (ret < 0)
785cf6eb489SMasami Hiramatsu 		return ret;
786cf6eb489SMasami Hiramatsu 
78792561cb7SMasami Hiramatsu 	dinfo = open_debuginfo(module, false);
788ff741783SMasami Hiramatsu 	if (!dinfo) {
789ee45b6c2SMasami Hiramatsu 		ret = -ENOENT;
790ee45b6c2SMasami Hiramatsu 		goto out;
791ff741783SMasami Hiramatsu 	}
792ff741783SMasami Hiramatsu 
793cc446446SMasami Hiramatsu 	setup_pager();
794cc446446SMasami Hiramatsu 
795ff741783SMasami Hiramatsu 	for (i = 0; i < npevs && ret >= 0; i++)
796ff741783SMasami Hiramatsu 		ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter,
797bd09d7b5SMasami Hiramatsu 					     externs);
798ff741783SMasami Hiramatsu 
799ff741783SMasami Hiramatsu 	debuginfo__delete(dinfo);
800ee45b6c2SMasami Hiramatsu out:
801ee45b6c2SMasami Hiramatsu 	exit_symbol_maps();
802cf6eb489SMasami Hiramatsu 	return ret;
803cf6eb489SMasami Hiramatsu }
804cf6eb489SMasami Hiramatsu 
80589fe808aSIngo Molnar #else	/* !HAVE_DWARF_SUPPORT */
8064b4da7f7SMasami Hiramatsu 
8075a6f6314SMasami Hiramatsu static int
8085a6f6314SMasami Hiramatsu find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused,
8095a6f6314SMasami Hiramatsu 				 struct perf_probe_point *pp __maybe_unused,
8105a6f6314SMasami Hiramatsu 				 bool is_kprobe __maybe_unused)
8114b4da7f7SMasami Hiramatsu {
8125a6f6314SMasami Hiramatsu 	return -ENOSYS;
8134b4da7f7SMasami Hiramatsu }
8144b4da7f7SMasami Hiramatsu 
8150e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
8161d037ca1SIrina Tirdea 				struct probe_trace_event **tevs __maybe_unused,
8171d027ee9SArnaldo Carvalho de Melo 				int max_tevs __maybe_unused,
8181d027ee9SArnaldo Carvalho de Melo 				const char *target __maybe_unused)
8194b4da7f7SMasami Hiramatsu {
820146a1439SMasami Hiramatsu 	if (perf_probe_event_need_dwarf(pev)) {
821146a1439SMasami Hiramatsu 		pr_warning("Debuginfo-analysis is not supported.\n");
822146a1439SMasami Hiramatsu 		return -ENOSYS;
823146a1439SMasami Hiramatsu 	}
824225466f1SSrikar Dronamraju 
8254b4da7f7SMasami Hiramatsu 	return 0;
8264b4da7f7SMasami Hiramatsu }
8274b4da7f7SMasami Hiramatsu 
8281d037ca1SIrina Tirdea int show_line_range(struct line_range *lr __maybe_unused,
8292b394bc4SMasami Hiramatsu 		    const char *module __maybe_unused,
8302b394bc4SMasami Hiramatsu 		    bool user __maybe_unused)
8314b4da7f7SMasami Hiramatsu {
832146a1439SMasami Hiramatsu 	pr_warning("Debuginfo-analysis is not supported.\n");
833146a1439SMasami Hiramatsu 	return -ENOSYS;
8344b4da7f7SMasami Hiramatsu }
8354b4da7f7SMasami Hiramatsu 
8361d037ca1SIrina Tirdea int show_available_vars(struct perf_probe_event *pevs __maybe_unused,
8371d037ca1SIrina Tirdea 			int npevs __maybe_unused, int max_vls __maybe_unused,
8381d037ca1SIrina Tirdea 			const char *module __maybe_unused,
8391d037ca1SIrina Tirdea 			struct strfilter *filter __maybe_unused,
8401d037ca1SIrina Tirdea 			bool externs __maybe_unused)
841cf6eb489SMasami Hiramatsu {
842cf6eb489SMasami Hiramatsu 	pr_warning("Debuginfo-analysis is not supported.\n");
843cf6eb489SMasami Hiramatsu 	return -ENOSYS;
844cf6eb489SMasami Hiramatsu }
845e0faa8d3SMasami Hiramatsu #endif
846e0faa8d3SMasami Hiramatsu 
847e53b00d3SMasami Hiramatsu void line_range__clear(struct line_range *lr)
848e53b00d3SMasami Hiramatsu {
849e53b00d3SMasami Hiramatsu 	free(lr->function);
850e53b00d3SMasami Hiramatsu 	free(lr->file);
851e53b00d3SMasami Hiramatsu 	free(lr->path);
852e53b00d3SMasami Hiramatsu 	free(lr->comp_dir);
8535a62257aSMasami Hiramatsu 	intlist__delete(lr->line_list);
854e53b00d3SMasami Hiramatsu 	memset(lr, 0, sizeof(*lr));
855e53b00d3SMasami Hiramatsu }
856e53b00d3SMasami Hiramatsu 
8575a62257aSMasami Hiramatsu int line_range__init(struct line_range *lr)
858e53b00d3SMasami Hiramatsu {
859e53b00d3SMasami Hiramatsu 	memset(lr, 0, sizeof(*lr));
8605a62257aSMasami Hiramatsu 	lr->line_list = intlist__new(NULL);
8615a62257aSMasami Hiramatsu 	if (!lr->line_list)
8625a62257aSMasami Hiramatsu 		return -ENOMEM;
8635a62257aSMasami Hiramatsu 	else
8645a62257aSMasami Hiramatsu 		return 0;
865e53b00d3SMasami Hiramatsu }
866e53b00d3SMasami Hiramatsu 
86721dd9ae5SFranck Bui-Huu static int parse_line_num(char **ptr, int *val, const char *what)
86821dd9ae5SFranck Bui-Huu {
86921dd9ae5SFranck Bui-Huu 	const char *start = *ptr;
87021dd9ae5SFranck Bui-Huu 
87121dd9ae5SFranck Bui-Huu 	errno = 0;
87221dd9ae5SFranck Bui-Huu 	*val = strtol(*ptr, ptr, 0);
87321dd9ae5SFranck Bui-Huu 	if (errno || *ptr == start) {
87421dd9ae5SFranck Bui-Huu 		semantic_error("'%s' is not a valid number.\n", what);
87521dd9ae5SFranck Bui-Huu 		return -EINVAL;
87621dd9ae5SFranck Bui-Huu 	}
87721dd9ae5SFranck Bui-Huu 	return 0;
87821dd9ae5SFranck Bui-Huu }
87921dd9ae5SFranck Bui-Huu 
8809d95b580SFranck Bui-Huu /*
8819d95b580SFranck Bui-Huu  * Stuff 'lr' according to the line range described by 'arg'.
8829d95b580SFranck Bui-Huu  * The line range syntax is described by:
8839d95b580SFranck Bui-Huu  *
8849d95b580SFranck Bui-Huu  *         SRC[:SLN[+NUM|-ELN]]
885e116dfa1SMasami Hiramatsu  *         FNC[@SRC][:SLN[+NUM|-ELN]]
8869d95b580SFranck Bui-Huu  */
887146a1439SMasami Hiramatsu int parse_line_range_desc(const char *arg, struct line_range *lr)
888631c9defSMasami Hiramatsu {
889e116dfa1SMasami Hiramatsu 	char *range, *file, *name = strdup(arg);
89021dd9ae5SFranck Bui-Huu 	int err;
8919d95b580SFranck Bui-Huu 
89221dd9ae5SFranck Bui-Huu 	if (!name)
89321dd9ae5SFranck Bui-Huu 		return -ENOMEM;
89421dd9ae5SFranck Bui-Huu 
89521dd9ae5SFranck Bui-Huu 	lr->start = 0;
89621dd9ae5SFranck Bui-Huu 	lr->end = INT_MAX;
89721dd9ae5SFranck Bui-Huu 
89821dd9ae5SFranck Bui-Huu 	range = strchr(name, ':');
89921dd9ae5SFranck Bui-Huu 	if (range) {
90021dd9ae5SFranck Bui-Huu 		*range++ = '\0';
90121dd9ae5SFranck Bui-Huu 
90221dd9ae5SFranck Bui-Huu 		err = parse_line_num(&range, &lr->start, "start line");
90321dd9ae5SFranck Bui-Huu 		if (err)
90421dd9ae5SFranck Bui-Huu 			goto err;
90521dd9ae5SFranck Bui-Huu 
90621dd9ae5SFranck Bui-Huu 		if (*range == '+' || *range == '-') {
90721dd9ae5SFranck Bui-Huu 			const char c = *range++;
90821dd9ae5SFranck Bui-Huu 
90921dd9ae5SFranck Bui-Huu 			err = parse_line_num(&range, &lr->end, "end line");
91021dd9ae5SFranck Bui-Huu 			if (err)
91121dd9ae5SFranck Bui-Huu 				goto err;
91221dd9ae5SFranck Bui-Huu 
91321dd9ae5SFranck Bui-Huu 			if (c == '+') {
91421dd9ae5SFranck Bui-Huu 				lr->end += lr->start;
91521dd9ae5SFranck Bui-Huu 				/*
916dda4ab34SMasami Hiramatsu 				 * Adjust the number of lines here.
917dda4ab34SMasami Hiramatsu 				 * If the number of lines == 1, the
918dda4ab34SMasami Hiramatsu 				 * the end of line should be equal to
919dda4ab34SMasami Hiramatsu 				 * the start of line.
920dda4ab34SMasami Hiramatsu 				 */
92121dd9ae5SFranck Bui-Huu 				lr->end--;
92221dd9ae5SFranck Bui-Huu 			}
92321dd9ae5SFranck Bui-Huu 		}
92421dd9ae5SFranck Bui-Huu 
925d3b63d7aSMasami Hiramatsu 		pr_debug("Line range is %d to %d\n", lr->start, lr->end);
92621dd9ae5SFranck Bui-Huu 
92721dd9ae5SFranck Bui-Huu 		err = -EINVAL;
928d3b63d7aSMasami Hiramatsu 		if (lr->start > lr->end) {
929631c9defSMasami Hiramatsu 			semantic_error("Start line must be smaller"
930146a1439SMasami Hiramatsu 				       " than end line.\n");
93121dd9ae5SFranck Bui-Huu 			goto err;
932146a1439SMasami Hiramatsu 		}
93321dd9ae5SFranck Bui-Huu 		if (*range != '\0') {
93421dd9ae5SFranck Bui-Huu 			semantic_error("Tailing with invalid str '%s'.\n", range);
93521dd9ae5SFranck Bui-Huu 			goto err;
936146a1439SMasami Hiramatsu 		}
937d3b63d7aSMasami Hiramatsu 	}
93802b95dadSMasami Hiramatsu 
939e116dfa1SMasami Hiramatsu 	file = strchr(name, '@');
940e116dfa1SMasami Hiramatsu 	if (file) {
941e116dfa1SMasami Hiramatsu 		*file = '\0';
942e116dfa1SMasami Hiramatsu 		lr->file = strdup(++file);
943e116dfa1SMasami Hiramatsu 		if (lr->file == NULL) {
944e116dfa1SMasami Hiramatsu 			err = -ENOMEM;
945e116dfa1SMasami Hiramatsu 			goto err;
946e116dfa1SMasami Hiramatsu 		}
947e116dfa1SMasami Hiramatsu 		lr->function = name;
948e116dfa1SMasami Hiramatsu 	} else if (strchr(name, '.'))
94921dd9ae5SFranck Bui-Huu 		lr->file = name;
950631c9defSMasami Hiramatsu 	else
95121dd9ae5SFranck Bui-Huu 		lr->function = name;
952146a1439SMasami Hiramatsu 
953146a1439SMasami Hiramatsu 	return 0;
95421dd9ae5SFranck Bui-Huu err:
95521dd9ae5SFranck Bui-Huu 	free(name);
95621dd9ae5SFranck Bui-Huu 	return err;
957631c9defSMasami Hiramatsu }
958631c9defSMasami Hiramatsu 
959b7702a21SMasami Hiramatsu /* Check the name is good for event/group */
960b7702a21SMasami Hiramatsu static bool check_event_name(const char *name)
961b7702a21SMasami Hiramatsu {
962b7702a21SMasami Hiramatsu 	if (!isalpha(*name) && *name != '_')
963b7702a21SMasami Hiramatsu 		return false;
964b7702a21SMasami Hiramatsu 	while (*++name != '\0') {
965b7702a21SMasami Hiramatsu 		if (!isalpha(*name) && !isdigit(*name) && *name != '_')
966b7702a21SMasami Hiramatsu 			return false;
967b7702a21SMasami Hiramatsu 	}
968b7702a21SMasami Hiramatsu 	return true;
969b7702a21SMasami Hiramatsu }
970b7702a21SMasami Hiramatsu 
97150656eecSMasami Hiramatsu /* Parse probepoint definition. */
972146a1439SMasami Hiramatsu static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
97350656eecSMasami Hiramatsu {
9744235b045SMasami Hiramatsu 	struct perf_probe_point *pp = &pev->point;
97550656eecSMasami Hiramatsu 	char *ptr, *tmp;
97650656eecSMasami Hiramatsu 	char c, nc = 0;
97750656eecSMasami Hiramatsu 	/*
97850656eecSMasami Hiramatsu 	 * <Syntax>
9792a9c8c36SMasami Hiramatsu 	 * perf probe [EVENT=]SRC[:LN|;PTN]
9802a9c8c36SMasami Hiramatsu 	 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
981af663d75SMasami Hiramatsu 	 *
982af663d75SMasami Hiramatsu 	 * TODO:Group name support
98350656eecSMasami Hiramatsu 	 */
98450656eecSMasami Hiramatsu 
9852a9c8c36SMasami Hiramatsu 	ptr = strpbrk(arg, ";=@+%");
9862a9c8c36SMasami Hiramatsu 	if (ptr && *ptr == '=') {	/* Event name */
987af663d75SMasami Hiramatsu 		*ptr = '\0';
988af663d75SMasami Hiramatsu 		tmp = ptr + 1;
989146a1439SMasami Hiramatsu 		if (strchr(arg, ':')) {
990146a1439SMasami Hiramatsu 			semantic_error("Group name is not supported yet.\n");
991146a1439SMasami Hiramatsu 			return -ENOTSUP;
992146a1439SMasami Hiramatsu 		}
993146a1439SMasami Hiramatsu 		if (!check_event_name(arg)) {
994b7702a21SMasami Hiramatsu 			semantic_error("%s is bad for event name -it must "
995146a1439SMasami Hiramatsu 				       "follow C symbol-naming rule.\n", arg);
996146a1439SMasami Hiramatsu 			return -EINVAL;
997146a1439SMasami Hiramatsu 		}
99802b95dadSMasami Hiramatsu 		pev->event = strdup(arg);
99902b95dadSMasami Hiramatsu 		if (pev->event == NULL)
100002b95dadSMasami Hiramatsu 			return -ENOMEM;
10014235b045SMasami Hiramatsu 		pev->group = NULL;
1002af663d75SMasami Hiramatsu 		arg = tmp;
1003af663d75SMasami Hiramatsu 	}
1004af663d75SMasami Hiramatsu 
10052a9c8c36SMasami Hiramatsu 	ptr = strpbrk(arg, ";:+@%");
100650656eecSMasami Hiramatsu 	if (ptr) {
100750656eecSMasami Hiramatsu 		nc = *ptr;
100850656eecSMasami Hiramatsu 		*ptr++ = '\0';
100950656eecSMasami Hiramatsu 	}
101050656eecSMasami Hiramatsu 
101102b95dadSMasami Hiramatsu 	tmp = strdup(arg);
101202b95dadSMasami Hiramatsu 	if (tmp == NULL)
101302b95dadSMasami Hiramatsu 		return -ENOMEM;
101402b95dadSMasami Hiramatsu 
101550656eecSMasami Hiramatsu 	/* Check arg is function or file and copy it */
101602b95dadSMasami Hiramatsu 	if (strchr(tmp, '.'))	/* File */
101702b95dadSMasami Hiramatsu 		pp->file = tmp;
101850656eecSMasami Hiramatsu 	else			/* Function */
101902b95dadSMasami Hiramatsu 		pp->function = tmp;
102050656eecSMasami Hiramatsu 
102150656eecSMasami Hiramatsu 	/* Parse other options */
102250656eecSMasami Hiramatsu 	while (ptr) {
102350656eecSMasami Hiramatsu 		arg = ptr;
102450656eecSMasami Hiramatsu 		c = nc;
10252a9c8c36SMasami Hiramatsu 		if (c == ';') {	/* Lazy pattern must be the last part */
102602b95dadSMasami Hiramatsu 			pp->lazy_line = strdup(arg);
102702b95dadSMasami Hiramatsu 			if (pp->lazy_line == NULL)
102802b95dadSMasami Hiramatsu 				return -ENOMEM;
10292a9c8c36SMasami Hiramatsu 			break;
10302a9c8c36SMasami Hiramatsu 		}
10312a9c8c36SMasami Hiramatsu 		ptr = strpbrk(arg, ";:+@%");
103250656eecSMasami Hiramatsu 		if (ptr) {
103350656eecSMasami Hiramatsu 			nc = *ptr;
103450656eecSMasami Hiramatsu 			*ptr++ = '\0';
103550656eecSMasami Hiramatsu 		}
103650656eecSMasami Hiramatsu 		switch (c) {
103750656eecSMasami Hiramatsu 		case ':':	/* Line number */
103850656eecSMasami Hiramatsu 			pp->line = strtoul(arg, &tmp, 0);
1039146a1439SMasami Hiramatsu 			if (*tmp != '\0') {
10402a9c8c36SMasami Hiramatsu 				semantic_error("There is non-digit char"
1041146a1439SMasami Hiramatsu 					       " in line number.\n");
1042146a1439SMasami Hiramatsu 				return -EINVAL;
1043146a1439SMasami Hiramatsu 			}
104450656eecSMasami Hiramatsu 			break;
104550656eecSMasami Hiramatsu 		case '+':	/* Byte offset from a symbol */
104650656eecSMasami Hiramatsu 			pp->offset = strtoul(arg, &tmp, 0);
1047146a1439SMasami Hiramatsu 			if (*tmp != '\0') {
10482a9c8c36SMasami Hiramatsu 				semantic_error("There is non-digit character"
1049146a1439SMasami Hiramatsu 						" in offset.\n");
1050146a1439SMasami Hiramatsu 				return -EINVAL;
1051146a1439SMasami Hiramatsu 			}
105250656eecSMasami Hiramatsu 			break;
105350656eecSMasami Hiramatsu 		case '@':	/* File name */
1054146a1439SMasami Hiramatsu 			if (pp->file) {
1055146a1439SMasami Hiramatsu 				semantic_error("SRC@SRC is not allowed.\n");
1056146a1439SMasami Hiramatsu 				return -EINVAL;
1057146a1439SMasami Hiramatsu 			}
105802b95dadSMasami Hiramatsu 			pp->file = strdup(arg);
105902b95dadSMasami Hiramatsu 			if (pp->file == NULL)
106002b95dadSMasami Hiramatsu 				return -ENOMEM;
106150656eecSMasami Hiramatsu 			break;
106250656eecSMasami Hiramatsu 		case '%':	/* Probe places */
106350656eecSMasami Hiramatsu 			if (strcmp(arg, "return") == 0) {
106450656eecSMasami Hiramatsu 				pp->retprobe = 1;
1065146a1439SMasami Hiramatsu 			} else {	/* Others not supported yet */
1066146a1439SMasami Hiramatsu 				semantic_error("%%%s is not supported.\n", arg);
1067146a1439SMasami Hiramatsu 				return -ENOTSUP;
1068146a1439SMasami Hiramatsu 			}
106950656eecSMasami Hiramatsu 			break;
1070146a1439SMasami Hiramatsu 		default:	/* Buggy case */
1071146a1439SMasami Hiramatsu 			pr_err("This program has a bug at %s:%d.\n",
1072146a1439SMasami Hiramatsu 				__FILE__, __LINE__);
1073146a1439SMasami Hiramatsu 			return -ENOTSUP;
107450656eecSMasami Hiramatsu 			break;
107550656eecSMasami Hiramatsu 		}
107650656eecSMasami Hiramatsu 	}
107750656eecSMasami Hiramatsu 
107850656eecSMasami Hiramatsu 	/* Exclusion check */
1079146a1439SMasami Hiramatsu 	if (pp->lazy_line && pp->line) {
10800e43e5d2SMasami Hiramatsu 		semantic_error("Lazy pattern can't be used with"
10810e43e5d2SMasami Hiramatsu 			       " line number.\n");
1082146a1439SMasami Hiramatsu 		return -EINVAL;
1083146a1439SMasami Hiramatsu 	}
10842a9c8c36SMasami Hiramatsu 
1085146a1439SMasami Hiramatsu 	if (pp->lazy_line && pp->offset) {
10860e43e5d2SMasami Hiramatsu 		semantic_error("Lazy pattern can't be used with offset.\n");
1087146a1439SMasami Hiramatsu 		return -EINVAL;
1088146a1439SMasami Hiramatsu 	}
10892a9c8c36SMasami Hiramatsu 
1090146a1439SMasami Hiramatsu 	if (pp->line && pp->offset) {
10910e43e5d2SMasami Hiramatsu 		semantic_error("Offset can't be used with line number.\n");
1092146a1439SMasami Hiramatsu 		return -EINVAL;
1093146a1439SMasami Hiramatsu 	}
109450656eecSMasami Hiramatsu 
1095146a1439SMasami Hiramatsu 	if (!pp->line && !pp->lazy_line && pp->file && !pp->function) {
10962a9c8c36SMasami Hiramatsu 		semantic_error("File always requires line number or "
10970e43e5d2SMasami Hiramatsu 			       "lazy pattern.\n");
1098146a1439SMasami Hiramatsu 		return -EINVAL;
1099146a1439SMasami Hiramatsu 	}
110050656eecSMasami Hiramatsu 
1101146a1439SMasami Hiramatsu 	if (pp->offset && !pp->function) {
11020e43e5d2SMasami Hiramatsu 		semantic_error("Offset requires an entry function.\n");
1103146a1439SMasami Hiramatsu 		return -EINVAL;
1104146a1439SMasami Hiramatsu 	}
110550656eecSMasami Hiramatsu 
1106146a1439SMasami Hiramatsu 	if (pp->retprobe && !pp->function) {
11070e43e5d2SMasami Hiramatsu 		semantic_error("Return probe requires an entry function.\n");
1108146a1439SMasami Hiramatsu 		return -EINVAL;
1109146a1439SMasami Hiramatsu 	}
111050656eecSMasami Hiramatsu 
1111146a1439SMasami Hiramatsu 	if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
11122a9c8c36SMasami Hiramatsu 		semantic_error("Offset/Line/Lazy pattern can't be used with "
11130e43e5d2SMasami Hiramatsu 			       "return probe.\n");
1114146a1439SMasami Hiramatsu 		return -EINVAL;
1115146a1439SMasami Hiramatsu 	}
111650656eecSMasami Hiramatsu 
11174235b045SMasami Hiramatsu 	pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
11182a9c8c36SMasami Hiramatsu 		 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
11192a9c8c36SMasami Hiramatsu 		 pp->lazy_line);
1120146a1439SMasami Hiramatsu 	return 0;
112150656eecSMasami Hiramatsu }
112250656eecSMasami Hiramatsu 
11237df2f329SMasami Hiramatsu /* Parse perf-probe event argument */
1124146a1439SMasami Hiramatsu static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
11257df2f329SMasami Hiramatsu {
1126b2a3c12bSMasami Hiramatsu 	char *tmp, *goodname;
11277df2f329SMasami Hiramatsu 	struct perf_probe_arg_field **fieldp;
11287df2f329SMasami Hiramatsu 
11297df2f329SMasami Hiramatsu 	pr_debug("parsing arg: %s into ", str);
11307df2f329SMasami Hiramatsu 
113148481938SMasami Hiramatsu 	tmp = strchr(str, '=');
113248481938SMasami Hiramatsu 	if (tmp) {
113302b95dadSMasami Hiramatsu 		arg->name = strndup(str, tmp - str);
113402b95dadSMasami Hiramatsu 		if (arg->name == NULL)
113502b95dadSMasami Hiramatsu 			return -ENOMEM;
113611a1ca35SMasami Hiramatsu 		pr_debug("name:%s ", arg->name);
113748481938SMasami Hiramatsu 		str = tmp + 1;
113848481938SMasami Hiramatsu 	}
113948481938SMasami Hiramatsu 
114011a1ca35SMasami Hiramatsu 	tmp = strchr(str, ':');
114111a1ca35SMasami Hiramatsu 	if (tmp) {	/* Type setting */
114211a1ca35SMasami Hiramatsu 		*tmp = '\0';
114302b95dadSMasami Hiramatsu 		arg->type = strdup(tmp + 1);
114402b95dadSMasami Hiramatsu 		if (arg->type == NULL)
114502b95dadSMasami Hiramatsu 			return -ENOMEM;
114611a1ca35SMasami Hiramatsu 		pr_debug("type:%s ", arg->type);
114711a1ca35SMasami Hiramatsu 	}
114811a1ca35SMasami Hiramatsu 
1149b2a3c12bSMasami Hiramatsu 	tmp = strpbrk(str, "-.[");
11507df2f329SMasami Hiramatsu 	if (!is_c_varname(str) || !tmp) {
11517df2f329SMasami Hiramatsu 		/* A variable, register, symbol or special value */
115202b95dadSMasami Hiramatsu 		arg->var = strdup(str);
115302b95dadSMasami Hiramatsu 		if (arg->var == NULL)
115402b95dadSMasami Hiramatsu 			return -ENOMEM;
115548481938SMasami Hiramatsu 		pr_debug("%s\n", arg->var);
1156146a1439SMasami Hiramatsu 		return 0;
11577df2f329SMasami Hiramatsu 	}
11587df2f329SMasami Hiramatsu 
1159b2a3c12bSMasami Hiramatsu 	/* Structure fields or array element */
116002b95dadSMasami Hiramatsu 	arg->var = strndup(str, tmp - str);
116102b95dadSMasami Hiramatsu 	if (arg->var == NULL)
116202b95dadSMasami Hiramatsu 		return -ENOMEM;
1163b2a3c12bSMasami Hiramatsu 	goodname = arg->var;
116448481938SMasami Hiramatsu 	pr_debug("%s, ", arg->var);
11657df2f329SMasami Hiramatsu 	fieldp = &arg->field;
11667df2f329SMasami Hiramatsu 
11677df2f329SMasami Hiramatsu 	do {
1168e334016fSMasami Hiramatsu 		*fieldp = zalloc(sizeof(struct perf_probe_arg_field));
1169e334016fSMasami Hiramatsu 		if (*fieldp == NULL)
1170e334016fSMasami Hiramatsu 			return -ENOMEM;
1171b2a3c12bSMasami Hiramatsu 		if (*tmp == '[') {	/* Array */
1172b2a3c12bSMasami Hiramatsu 			str = tmp;
1173b2a3c12bSMasami Hiramatsu 			(*fieldp)->index = strtol(str + 1, &tmp, 0);
1174b2a3c12bSMasami Hiramatsu 			(*fieldp)->ref = true;
1175b2a3c12bSMasami Hiramatsu 			if (*tmp != ']' || tmp == str + 1) {
1176b2a3c12bSMasami Hiramatsu 				semantic_error("Array index must be a"
1177b2a3c12bSMasami Hiramatsu 						" number.\n");
1178b2a3c12bSMasami Hiramatsu 				return -EINVAL;
1179b2a3c12bSMasami Hiramatsu 			}
1180b2a3c12bSMasami Hiramatsu 			tmp++;
1181b2a3c12bSMasami Hiramatsu 			if (*tmp == '\0')
1182b2a3c12bSMasami Hiramatsu 				tmp = NULL;
1183b2a3c12bSMasami Hiramatsu 		} else {		/* Structure */
11847df2f329SMasami Hiramatsu 			if (*tmp == '.') {
11857df2f329SMasami Hiramatsu 				str = tmp + 1;
11867df2f329SMasami Hiramatsu 				(*fieldp)->ref = false;
11877df2f329SMasami Hiramatsu 			} else if (tmp[1] == '>') {
11887df2f329SMasami Hiramatsu 				str = tmp + 2;
11897df2f329SMasami Hiramatsu 				(*fieldp)->ref = true;
1190146a1439SMasami Hiramatsu 			} else {
1191b2a3c12bSMasami Hiramatsu 				semantic_error("Argument parse error: %s\n",
1192b2a3c12bSMasami Hiramatsu 					       str);
1193146a1439SMasami Hiramatsu 				return -EINVAL;
1194146a1439SMasami Hiramatsu 			}
1195b2a3c12bSMasami Hiramatsu 			tmp = strpbrk(str, "-.[");
1196b2a3c12bSMasami Hiramatsu 		}
11977df2f329SMasami Hiramatsu 		if (tmp) {
119802b95dadSMasami Hiramatsu 			(*fieldp)->name = strndup(str, tmp - str);
119902b95dadSMasami Hiramatsu 			if ((*fieldp)->name == NULL)
120002b95dadSMasami Hiramatsu 				return -ENOMEM;
1201b2a3c12bSMasami Hiramatsu 			if (*str != '[')
1202b2a3c12bSMasami Hiramatsu 				goodname = (*fieldp)->name;
12037df2f329SMasami Hiramatsu 			pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
12047df2f329SMasami Hiramatsu 			fieldp = &(*fieldp)->next;
12057df2f329SMasami Hiramatsu 		}
12067df2f329SMasami Hiramatsu 	} while (tmp);
120702b95dadSMasami Hiramatsu 	(*fieldp)->name = strdup(str);
120802b95dadSMasami Hiramatsu 	if ((*fieldp)->name == NULL)
120902b95dadSMasami Hiramatsu 		return -ENOMEM;
1210b2a3c12bSMasami Hiramatsu 	if (*str != '[')
1211b2a3c12bSMasami Hiramatsu 		goodname = (*fieldp)->name;
12127df2f329SMasami Hiramatsu 	pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
1213df0faf4bSMasami Hiramatsu 
1214b2a3c12bSMasami Hiramatsu 	/* If no name is specified, set the last field name (not array index)*/
121502b95dadSMasami Hiramatsu 	if (!arg->name) {
1216b2a3c12bSMasami Hiramatsu 		arg->name = strdup(goodname);
121702b95dadSMasami Hiramatsu 		if (arg->name == NULL)
121802b95dadSMasami Hiramatsu 			return -ENOMEM;
121902b95dadSMasami Hiramatsu 	}
1220146a1439SMasami Hiramatsu 	return 0;
12217df2f329SMasami Hiramatsu }
12227df2f329SMasami Hiramatsu 
12234235b045SMasami Hiramatsu /* Parse perf-probe event command */
1224146a1439SMasami Hiramatsu int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
122550656eecSMasami Hiramatsu {
1226e1c01d61SMasami Hiramatsu 	char **argv;
1227146a1439SMasami Hiramatsu 	int argc, i, ret = 0;
1228fac13fd5SMasami Hiramatsu 
12294235b045SMasami Hiramatsu 	argv = argv_split(cmd, &argc);
1230146a1439SMasami Hiramatsu 	if (!argv) {
1231146a1439SMasami Hiramatsu 		pr_debug("Failed to split arguments.\n");
1232146a1439SMasami Hiramatsu 		return -ENOMEM;
1233146a1439SMasami Hiramatsu 	}
1234146a1439SMasami Hiramatsu 	if (argc - 1 > MAX_PROBE_ARGS) {
1235146a1439SMasami Hiramatsu 		semantic_error("Too many probe arguments (%d).\n", argc - 1);
1236146a1439SMasami Hiramatsu 		ret = -ERANGE;
1237146a1439SMasami Hiramatsu 		goto out;
1238146a1439SMasami Hiramatsu 	}
123950656eecSMasami Hiramatsu 	/* Parse probe point */
1240146a1439SMasami Hiramatsu 	ret = parse_perf_probe_point(argv[0], pev);
1241146a1439SMasami Hiramatsu 	if (ret < 0)
1242146a1439SMasami Hiramatsu 		goto out;
124350656eecSMasami Hiramatsu 
1244e1c01d61SMasami Hiramatsu 	/* Copy arguments and ensure return probe has no C argument */
12454235b045SMasami Hiramatsu 	pev->nargs = argc - 1;
1246e334016fSMasami Hiramatsu 	pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
1247e334016fSMasami Hiramatsu 	if (pev->args == NULL) {
1248e334016fSMasami Hiramatsu 		ret = -ENOMEM;
1249e334016fSMasami Hiramatsu 		goto out;
1250e334016fSMasami Hiramatsu 	}
1251146a1439SMasami Hiramatsu 	for (i = 0; i < pev->nargs && ret >= 0; i++) {
1252146a1439SMasami Hiramatsu 		ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]);
1253146a1439SMasami Hiramatsu 		if (ret >= 0 &&
1254146a1439SMasami Hiramatsu 		    is_c_varname(pev->args[i].var) && pev->point.retprobe) {
12554235b045SMasami Hiramatsu 			semantic_error("You can't specify local variable for"
1256146a1439SMasami Hiramatsu 				       " kretprobe.\n");
1257146a1439SMasami Hiramatsu 			ret = -EINVAL;
1258e1c01d61SMasami Hiramatsu 		}
1259146a1439SMasami Hiramatsu 	}
1260146a1439SMasami Hiramatsu out:
1261e1c01d61SMasami Hiramatsu 	argv_free(argv);
1262146a1439SMasami Hiramatsu 
1263146a1439SMasami Hiramatsu 	return ret;
126450656eecSMasami Hiramatsu }
126550656eecSMasami Hiramatsu 
12664235b045SMasami Hiramatsu /* Return true if this perf_probe_event requires debuginfo */
12674235b045SMasami Hiramatsu bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
12684de189feSMasami Hiramatsu {
12694235b045SMasami Hiramatsu 	int i;
12704235b045SMasami Hiramatsu 
12714235b045SMasami Hiramatsu 	if (pev->point.file || pev->point.line || pev->point.lazy_line)
12724235b045SMasami Hiramatsu 		return true;
12734235b045SMasami Hiramatsu 
12744235b045SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++)
127548481938SMasami Hiramatsu 		if (is_c_varname(pev->args[i].var))
12764235b045SMasami Hiramatsu 			return true;
12774235b045SMasami Hiramatsu 
12784235b045SMasami Hiramatsu 	return false;
12794235b045SMasami Hiramatsu }
12804235b045SMasami Hiramatsu 
12810e60836bSSrikar Dronamraju /* Parse probe_events event into struct probe_point */
12820e60836bSSrikar Dronamraju static int parse_probe_trace_command(const char *cmd,
12830e60836bSSrikar Dronamraju 				     struct probe_trace_event *tev)
12844235b045SMasami Hiramatsu {
12850e60836bSSrikar Dronamraju 	struct probe_trace_point *tp = &tev->point;
12864de189feSMasami Hiramatsu 	char pr;
12874de189feSMasami Hiramatsu 	char *p;
1288bcbd0040SIrina Tirdea 	char *argv0_str = NULL, *fmt, *fmt1_str, *fmt2_str, *fmt3_str;
12894de189feSMasami Hiramatsu 	int ret, i, argc;
12904de189feSMasami Hiramatsu 	char **argv;
12914de189feSMasami Hiramatsu 
12920e60836bSSrikar Dronamraju 	pr_debug("Parsing probe_events: %s\n", cmd);
12934235b045SMasami Hiramatsu 	argv = argv_split(cmd, &argc);
1294146a1439SMasami Hiramatsu 	if (!argv) {
1295146a1439SMasami Hiramatsu 		pr_debug("Failed to split arguments.\n");
1296146a1439SMasami Hiramatsu 		return -ENOMEM;
1297146a1439SMasami Hiramatsu 	}
1298146a1439SMasami Hiramatsu 	if (argc < 2) {
1299146a1439SMasami Hiramatsu 		semantic_error("Too few probe arguments.\n");
1300146a1439SMasami Hiramatsu 		ret = -ERANGE;
1301146a1439SMasami Hiramatsu 		goto out;
1302146a1439SMasami Hiramatsu 	}
13034de189feSMasami Hiramatsu 
13044de189feSMasami Hiramatsu 	/* Scan event and group name. */
1305bcbd0040SIrina Tirdea 	argv0_str = strdup(argv[0]);
1306bcbd0040SIrina Tirdea 	if (argv0_str == NULL) {
1307bcbd0040SIrina Tirdea 		ret = -ENOMEM;
1308bcbd0040SIrina Tirdea 		goto out;
1309bcbd0040SIrina Tirdea 	}
1310bcbd0040SIrina Tirdea 	fmt1_str = strtok_r(argv0_str, ":", &fmt);
1311bcbd0040SIrina Tirdea 	fmt2_str = strtok_r(NULL, "/", &fmt);
1312bcbd0040SIrina Tirdea 	fmt3_str = strtok_r(NULL, " \t", &fmt);
1313bcbd0040SIrina Tirdea 	if (fmt1_str == NULL || strlen(fmt1_str) != 1 || fmt2_str == NULL
1314bcbd0040SIrina Tirdea 	    || fmt3_str == NULL) {
1315146a1439SMasami Hiramatsu 		semantic_error("Failed to parse event name: %s\n", argv[0]);
1316146a1439SMasami Hiramatsu 		ret = -EINVAL;
1317146a1439SMasami Hiramatsu 		goto out;
1318146a1439SMasami Hiramatsu 	}
1319bcbd0040SIrina Tirdea 	pr = fmt1_str[0];
1320bcbd0040SIrina Tirdea 	tev->group = strdup(fmt2_str);
1321bcbd0040SIrina Tirdea 	tev->event = strdup(fmt3_str);
1322bcbd0040SIrina Tirdea 	if (tev->group == NULL || tev->event == NULL) {
1323bcbd0040SIrina Tirdea 		ret = -ENOMEM;
1324bcbd0040SIrina Tirdea 		goto out;
1325bcbd0040SIrina Tirdea 	}
13264235b045SMasami Hiramatsu 	pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr);
13274de189feSMasami Hiramatsu 
13284235b045SMasami Hiramatsu 	tp->retprobe = (pr == 'r');
13294de189feSMasami Hiramatsu 
1330190b57fcSMasami Hiramatsu 	/* Scan module name(if there), function name and offset */
1331190b57fcSMasami Hiramatsu 	p = strchr(argv[1], ':');
1332190b57fcSMasami Hiramatsu 	if (p) {
1333190b57fcSMasami Hiramatsu 		tp->module = strndup(argv[1], p - argv[1]);
1334190b57fcSMasami Hiramatsu 		p++;
1335190b57fcSMasami Hiramatsu 	} else
1336190b57fcSMasami Hiramatsu 		p = argv[1];
1337bcbd0040SIrina Tirdea 	fmt1_str = strtok_r(p, "+", &fmt);
13385a6f6314SMasami Hiramatsu 	if (fmt1_str[0] == '0')	/* only the address started with 0x */
13395a6f6314SMasami Hiramatsu 		tp->address = strtoul(fmt1_str, NULL, 0);
13405a6f6314SMasami Hiramatsu 	else {
13415a6f6314SMasami Hiramatsu 		/* Only the symbol-based probe has offset */
1342bcbd0040SIrina Tirdea 		tp->symbol = strdup(fmt1_str);
1343bcbd0040SIrina Tirdea 		if (tp->symbol == NULL) {
1344bcbd0040SIrina Tirdea 			ret = -ENOMEM;
1345bcbd0040SIrina Tirdea 			goto out;
1346bcbd0040SIrina Tirdea 		}
1347bcbd0040SIrina Tirdea 		fmt2_str = strtok_r(NULL, "", &fmt);
1348bcbd0040SIrina Tirdea 		if (fmt2_str == NULL)
13494235b045SMasami Hiramatsu 			tp->offset = 0;
1350bcbd0040SIrina Tirdea 		else
1351bcbd0040SIrina Tirdea 			tp->offset = strtoul(fmt2_str, NULL, 10);
13525a6f6314SMasami Hiramatsu 	}
13534de189feSMasami Hiramatsu 
13544235b045SMasami Hiramatsu 	tev->nargs = argc - 2;
13550e60836bSSrikar Dronamraju 	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
1356e334016fSMasami Hiramatsu 	if (tev->args == NULL) {
1357e334016fSMasami Hiramatsu 		ret = -ENOMEM;
1358e334016fSMasami Hiramatsu 		goto out;
1359e334016fSMasami Hiramatsu 	}
13604235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
13614de189feSMasami Hiramatsu 		p = strchr(argv[i + 2], '=');
13624de189feSMasami Hiramatsu 		if (p)	/* We don't need which register is assigned. */
13634235b045SMasami Hiramatsu 			*p++ = '\0';
13644235b045SMasami Hiramatsu 		else
13654235b045SMasami Hiramatsu 			p = argv[i + 2];
136602b95dadSMasami Hiramatsu 		tev->args[i].name = strdup(argv[i + 2]);
13674235b045SMasami Hiramatsu 		/* TODO: parse regs and offset */
136802b95dadSMasami Hiramatsu 		tev->args[i].value = strdup(p);
136902b95dadSMasami Hiramatsu 		if (tev->args[i].name == NULL || tev->args[i].value == NULL) {
137002b95dadSMasami Hiramatsu 			ret = -ENOMEM;
137102b95dadSMasami Hiramatsu 			goto out;
137202b95dadSMasami Hiramatsu 		}
13734de189feSMasami Hiramatsu 	}
1374146a1439SMasami Hiramatsu 	ret = 0;
1375146a1439SMasami Hiramatsu out:
1376bcbd0040SIrina Tirdea 	free(argv0_str);
13774de189feSMasami Hiramatsu 	argv_free(argv);
1378146a1439SMasami Hiramatsu 	return ret;
13794de189feSMasami Hiramatsu }
13804de189feSMasami Hiramatsu 
13817df2f329SMasami Hiramatsu /* Compose only probe arg */
13827df2f329SMasami Hiramatsu int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
13837df2f329SMasami Hiramatsu {
13847df2f329SMasami Hiramatsu 	struct perf_probe_arg_field *field = pa->field;
13857df2f329SMasami Hiramatsu 	int ret;
13867df2f329SMasami Hiramatsu 	char *tmp = buf;
13877df2f329SMasami Hiramatsu 
138848481938SMasami Hiramatsu 	if (pa->name && pa->var)
138948481938SMasami Hiramatsu 		ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var);
139048481938SMasami Hiramatsu 	else
139148481938SMasami Hiramatsu 		ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var);
13927df2f329SMasami Hiramatsu 	if (ret <= 0)
13937df2f329SMasami Hiramatsu 		goto error;
13947df2f329SMasami Hiramatsu 	tmp += ret;
13957df2f329SMasami Hiramatsu 	len -= ret;
13967df2f329SMasami Hiramatsu 
13977df2f329SMasami Hiramatsu 	while (field) {
1398b2a3c12bSMasami Hiramatsu 		if (field->name[0] == '[')
1399b2a3c12bSMasami Hiramatsu 			ret = e_snprintf(tmp, len, "%s", field->name);
1400b2a3c12bSMasami Hiramatsu 		else
1401b2a3c12bSMasami Hiramatsu 			ret = e_snprintf(tmp, len, "%s%s",
1402b2a3c12bSMasami Hiramatsu 					 field->ref ? "->" : ".", field->name);
14037df2f329SMasami Hiramatsu 		if (ret <= 0)
14047df2f329SMasami Hiramatsu 			goto error;
14057df2f329SMasami Hiramatsu 		tmp += ret;
14067df2f329SMasami Hiramatsu 		len -= ret;
14077df2f329SMasami Hiramatsu 		field = field->next;
14087df2f329SMasami Hiramatsu 	}
140911a1ca35SMasami Hiramatsu 
141011a1ca35SMasami Hiramatsu 	if (pa->type) {
141111a1ca35SMasami Hiramatsu 		ret = e_snprintf(tmp, len, ":%s", pa->type);
141211a1ca35SMasami Hiramatsu 		if (ret <= 0)
141311a1ca35SMasami Hiramatsu 			goto error;
141411a1ca35SMasami Hiramatsu 		tmp += ret;
141511a1ca35SMasami Hiramatsu 		len -= ret;
141611a1ca35SMasami Hiramatsu 	}
141711a1ca35SMasami Hiramatsu 
14187df2f329SMasami Hiramatsu 	return tmp - buf;
14197df2f329SMasami Hiramatsu error:
14205f03cba4SMasami Hiramatsu 	pr_debug("Failed to synthesize perf probe argument: %d\n", ret);
1421146a1439SMasami Hiramatsu 	return ret;
14227df2f329SMasami Hiramatsu }
14237df2f329SMasami Hiramatsu 
14244235b045SMasami Hiramatsu /* Compose only probe point (not argument) */
14254235b045SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
142650656eecSMasami Hiramatsu {
1427fb1587d8SMasami Hiramatsu 	char *buf, *tmp;
1428fb1587d8SMasami Hiramatsu 	char offs[32] = "", line[32] = "", file[32] = "";
1429fb1587d8SMasami Hiramatsu 	int ret, len;
143050656eecSMasami Hiramatsu 
1431e334016fSMasami Hiramatsu 	buf = zalloc(MAX_CMDLEN);
1432e334016fSMasami Hiramatsu 	if (buf == NULL) {
1433e334016fSMasami Hiramatsu 		ret = -ENOMEM;
1434e334016fSMasami Hiramatsu 		goto error;
1435e334016fSMasami Hiramatsu 	}
14364de189feSMasami Hiramatsu 	if (pp->offset) {
1437fb1587d8SMasami Hiramatsu 		ret = e_snprintf(offs, 32, "+%lu", pp->offset);
14384de189feSMasami Hiramatsu 		if (ret <= 0)
14394de189feSMasami Hiramatsu 			goto error;
14404de189feSMasami Hiramatsu 	}
14414de189feSMasami Hiramatsu 	if (pp->line) {
1442fb1587d8SMasami Hiramatsu 		ret = e_snprintf(line, 32, ":%d", pp->line);
1443fb1587d8SMasami Hiramatsu 		if (ret <= 0)
1444fb1587d8SMasami Hiramatsu 			goto error;
1445fb1587d8SMasami Hiramatsu 	}
1446fb1587d8SMasami Hiramatsu 	if (pp->file) {
144732ae2adeSFranck Bui-Huu 		tmp = pp->file;
144832ae2adeSFranck Bui-Huu 		len = strlen(tmp);
144932ae2adeSFranck Bui-Huu 		if (len > 30) {
145032ae2adeSFranck Bui-Huu 			tmp = strchr(pp->file + len - 30, '/');
145132ae2adeSFranck Bui-Huu 			tmp = tmp ? tmp + 1 : pp->file + len - 30;
145232ae2adeSFranck Bui-Huu 		}
145332ae2adeSFranck Bui-Huu 		ret = e_snprintf(file, 32, "@%s", tmp);
14544de189feSMasami Hiramatsu 		if (ret <= 0)
14554de189feSMasami Hiramatsu 			goto error;
14564de189feSMasami Hiramatsu 	}
14574de189feSMasami Hiramatsu 
14584de189feSMasami Hiramatsu 	if (pp->function)
1459fb1587d8SMasami Hiramatsu 		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function,
1460fb1587d8SMasami Hiramatsu 				 offs, pp->retprobe ? "%return" : "", line,
1461fb1587d8SMasami Hiramatsu 				 file);
14624de189feSMasami Hiramatsu 	else
1463fb1587d8SMasami Hiramatsu 		ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line);
14644235b045SMasami Hiramatsu 	if (ret <= 0)
14654235b045SMasami Hiramatsu 		goto error;
14664235b045SMasami Hiramatsu 
14674235b045SMasami Hiramatsu 	return buf;
14684235b045SMasami Hiramatsu error:
14695f03cba4SMasami Hiramatsu 	pr_debug("Failed to synthesize perf probe point: %d\n", ret);
1470146a1439SMasami Hiramatsu 	free(buf);
1471146a1439SMasami Hiramatsu 	return NULL;
14724235b045SMasami Hiramatsu }
14734235b045SMasami Hiramatsu 
14744235b045SMasami Hiramatsu #if 0
14754235b045SMasami Hiramatsu char *synthesize_perf_probe_command(struct perf_probe_event *pev)
14764235b045SMasami Hiramatsu {
14774235b045SMasami Hiramatsu 	char *buf;
14784235b045SMasami Hiramatsu 	int i, len, ret;
14794235b045SMasami Hiramatsu 
14804235b045SMasami Hiramatsu 	buf = synthesize_perf_probe_point(&pev->point);
14814235b045SMasami Hiramatsu 	if (!buf)
14824235b045SMasami Hiramatsu 		return NULL;
14834235b045SMasami Hiramatsu 
14844235b045SMasami Hiramatsu 	len = strlen(buf);
14854235b045SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++) {
14864235b045SMasami Hiramatsu 		ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s",
14874235b045SMasami Hiramatsu 				 pev->args[i].name);
14887ef17aafSMasami Hiramatsu 		if (ret <= 0) {
14894235b045SMasami Hiramatsu 			free(buf);
14904235b045SMasami Hiramatsu 			return NULL;
14917ef17aafSMasami Hiramatsu 		}
14924235b045SMasami Hiramatsu 		len += ret;
14937ef17aafSMasami Hiramatsu 	}
149450656eecSMasami Hiramatsu 
14954235b045SMasami Hiramatsu 	return buf;
14964235b045SMasami Hiramatsu }
14974235b045SMasami Hiramatsu #endif
14984235b045SMasami Hiramatsu 
14990e60836bSSrikar Dronamraju static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
15004235b045SMasami Hiramatsu 					     char **buf, size_t *buflen,
15014235b045SMasami Hiramatsu 					     int depth)
15027ef17aafSMasami Hiramatsu {
15034235b045SMasami Hiramatsu 	int ret;
15044235b045SMasami Hiramatsu 	if (ref->next) {
15050e60836bSSrikar Dronamraju 		depth = __synthesize_probe_trace_arg_ref(ref->next, buf,
15064235b045SMasami Hiramatsu 							 buflen, depth + 1);
15074235b045SMasami Hiramatsu 		if (depth < 0)
15084235b045SMasami Hiramatsu 			goto out;
15094235b045SMasami Hiramatsu 	}
15104235b045SMasami Hiramatsu 
15114235b045SMasami Hiramatsu 	ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset);
15124235b045SMasami Hiramatsu 	if (ret < 0)
15134235b045SMasami Hiramatsu 		depth = ret;
15144235b045SMasami Hiramatsu 	else {
15154235b045SMasami Hiramatsu 		*buf += ret;
15164235b045SMasami Hiramatsu 		*buflen -= ret;
15174235b045SMasami Hiramatsu 	}
15184235b045SMasami Hiramatsu out:
15194235b045SMasami Hiramatsu 	return depth;
15204235b045SMasami Hiramatsu 
15214235b045SMasami Hiramatsu }
15224235b045SMasami Hiramatsu 
15230e60836bSSrikar Dronamraju static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
15244235b045SMasami Hiramatsu 				       char *buf, size_t buflen)
15254235b045SMasami Hiramatsu {
15260e60836bSSrikar Dronamraju 	struct probe_trace_arg_ref *ref = arg->ref;
15274235b045SMasami Hiramatsu 	int ret, depth = 0;
15284235b045SMasami Hiramatsu 	char *tmp = buf;
15294235b045SMasami Hiramatsu 
15304235b045SMasami Hiramatsu 	/* Argument name or separator */
15314235b045SMasami Hiramatsu 	if (arg->name)
15324235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, " %s=", arg->name);
15334235b045SMasami Hiramatsu 	else
15344235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, " ");
15354235b045SMasami Hiramatsu 	if (ret < 0)
15364235b045SMasami Hiramatsu 		return ret;
15374235b045SMasami Hiramatsu 	buf += ret;
15384235b045SMasami Hiramatsu 	buflen -= ret;
15394235b045SMasami Hiramatsu 
1540b7dcb857SMasami Hiramatsu 	/* Special case: @XXX */
1541b7dcb857SMasami Hiramatsu 	if (arg->value[0] == '@' && arg->ref)
1542b7dcb857SMasami Hiramatsu 			ref = ref->next;
1543b7dcb857SMasami Hiramatsu 
15444235b045SMasami Hiramatsu 	/* Dereferencing arguments */
1545b7dcb857SMasami Hiramatsu 	if (ref) {
15460e60836bSSrikar Dronamraju 		depth = __synthesize_probe_trace_arg_ref(ref, &buf,
15474235b045SMasami Hiramatsu 							  &buflen, 1);
15484235b045SMasami Hiramatsu 		if (depth < 0)
15494235b045SMasami Hiramatsu 			return depth;
15504235b045SMasami Hiramatsu 	}
15514235b045SMasami Hiramatsu 
15524235b045SMasami Hiramatsu 	/* Print argument value */
1553b7dcb857SMasami Hiramatsu 	if (arg->value[0] == '@' && arg->ref)
1554b7dcb857SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, "%s%+ld", arg->value,
1555b7dcb857SMasami Hiramatsu 				 arg->ref->offset);
1556b7dcb857SMasami Hiramatsu 	else
15574235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, "%s", arg->value);
15584235b045SMasami Hiramatsu 	if (ret < 0)
15594235b045SMasami Hiramatsu 		return ret;
15604235b045SMasami Hiramatsu 	buf += ret;
15614235b045SMasami Hiramatsu 	buflen -= ret;
15624235b045SMasami Hiramatsu 
15634235b045SMasami Hiramatsu 	/* Closing */
15644235b045SMasami Hiramatsu 	while (depth--) {
15654235b045SMasami Hiramatsu 		ret = e_snprintf(buf, buflen, ")");
15664235b045SMasami Hiramatsu 		if (ret < 0)
15674235b045SMasami Hiramatsu 			return ret;
15684235b045SMasami Hiramatsu 		buf += ret;
15694235b045SMasami Hiramatsu 		buflen -= ret;
15704235b045SMasami Hiramatsu 	}
15714984912eSMasami Hiramatsu 	/* Print argument type */
15724984912eSMasami Hiramatsu 	if (arg->type) {
15734984912eSMasami Hiramatsu 		ret = e_snprintf(buf, buflen, ":%s", arg->type);
15744984912eSMasami Hiramatsu 		if (ret <= 0)
15754984912eSMasami Hiramatsu 			return ret;
15764984912eSMasami Hiramatsu 		buf += ret;
15774984912eSMasami Hiramatsu 	}
15784235b045SMasami Hiramatsu 
15794235b045SMasami Hiramatsu 	return buf - tmp;
15804235b045SMasami Hiramatsu }
15814235b045SMasami Hiramatsu 
15820e60836bSSrikar Dronamraju char *synthesize_probe_trace_command(struct probe_trace_event *tev)
15834235b045SMasami Hiramatsu {
15840e60836bSSrikar Dronamraju 	struct probe_trace_point *tp = &tev->point;
15857ef17aafSMasami Hiramatsu 	char *buf;
15867ef17aafSMasami Hiramatsu 	int i, len, ret;
15877ef17aafSMasami Hiramatsu 
1588e334016fSMasami Hiramatsu 	buf = zalloc(MAX_CMDLEN);
1589e334016fSMasami Hiramatsu 	if (buf == NULL)
1590e334016fSMasami Hiramatsu 		return NULL;
1591e334016fSMasami Hiramatsu 
1592eb948e50SMasami Hiramatsu 	len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p',
1593eb948e50SMasami Hiramatsu 			 tev->group, tev->event);
1594eb948e50SMasami Hiramatsu 	if (len <= 0)
1595eb948e50SMasami Hiramatsu 		goto error;
1596eb948e50SMasami Hiramatsu 
1597eb948e50SMasami Hiramatsu 	/* Uprobes must have tp->address and tp->module */
1598eb948e50SMasami Hiramatsu 	if (tev->uprobes && (!tp->address || !tp->module))
1599eb948e50SMasami Hiramatsu 		goto error;
1600eb948e50SMasami Hiramatsu 
1601eb948e50SMasami Hiramatsu 	/* Use the tp->address for uprobes */
1602225466f1SSrikar Dronamraju 	if (tev->uprobes)
1603eb948e50SMasami Hiramatsu 		ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx",
1604eb948e50SMasami Hiramatsu 				 tp->module, tp->address);
1605225466f1SSrikar Dronamraju 	else
1606eb948e50SMasami Hiramatsu 		ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu",
1607190b57fcSMasami Hiramatsu 				 tp->module ?: "", tp->module ? ":" : "",
16084235b045SMasami Hiramatsu 				 tp->symbol, tp->offset);
1609225466f1SSrikar Dronamraju 
1610eb948e50SMasami Hiramatsu 	if (ret <= 0)
16114235b045SMasami Hiramatsu 		goto error;
1612eb948e50SMasami Hiramatsu 	len += ret;
16137ef17aafSMasami Hiramatsu 
16144235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
16150e60836bSSrikar Dronamraju 		ret = synthesize_probe_trace_arg(&tev->args[i], buf + len,
16164235b045SMasami Hiramatsu 						  MAX_CMDLEN - len);
16174de189feSMasami Hiramatsu 		if (ret <= 0)
161850656eecSMasami Hiramatsu 			goto error;
161950656eecSMasami Hiramatsu 		len += ret;
162050656eecSMasami Hiramatsu 	}
162150656eecSMasami Hiramatsu 
16224235b045SMasami Hiramatsu 	return buf;
162350656eecSMasami Hiramatsu error:
16244235b045SMasami Hiramatsu 	free(buf);
16254235b045SMasami Hiramatsu 	return NULL;
162650656eecSMasami Hiramatsu }
162750656eecSMasami Hiramatsu 
16285a6f6314SMasami Hiramatsu static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
16295a6f6314SMasami Hiramatsu 					  struct perf_probe_point *pp,
16305a6f6314SMasami Hiramatsu 					  bool is_kprobe)
16315a6f6314SMasami Hiramatsu {
16325a6f6314SMasami Hiramatsu 	struct symbol *sym = NULL;
16335a6f6314SMasami Hiramatsu 	struct map *map;
16345a6f6314SMasami Hiramatsu 	u64 addr;
16355a6f6314SMasami Hiramatsu 	int ret = -ENOENT;
16365a6f6314SMasami Hiramatsu 
16375a6f6314SMasami Hiramatsu 	if (!is_kprobe) {
16385a6f6314SMasami Hiramatsu 		map = dso__new_map(tp->module);
16395a6f6314SMasami Hiramatsu 		if (!map)
16405a6f6314SMasami Hiramatsu 			goto out;
16415a6f6314SMasami Hiramatsu 		addr = tp->address;
16425a6f6314SMasami Hiramatsu 		sym = map__find_symbol(map, addr, NULL);
16435a6f6314SMasami Hiramatsu 	} else {
16445a6f6314SMasami Hiramatsu 		addr = kernel_get_symbol_address_by_name(tp->symbol, true);
16455a6f6314SMasami Hiramatsu 		if (addr) {
16465a6f6314SMasami Hiramatsu 			addr += tp->offset;
16475a6f6314SMasami Hiramatsu 			sym = __find_kernel_function(addr, &map);
16485a6f6314SMasami Hiramatsu 		}
16495a6f6314SMasami Hiramatsu 	}
16505a6f6314SMasami Hiramatsu 	if (!sym)
16515a6f6314SMasami Hiramatsu 		goto out;
16525a6f6314SMasami Hiramatsu 
16535a6f6314SMasami Hiramatsu 	pp->retprobe = tp->retprobe;
16545a6f6314SMasami Hiramatsu 	pp->offset = addr - map->unmap_ip(map, sym->start);
16555a6f6314SMasami Hiramatsu 	pp->function = strdup(sym->name);
16565a6f6314SMasami Hiramatsu 	ret = pp->function ? 0 : -ENOMEM;
16575a6f6314SMasami Hiramatsu 
16585a6f6314SMasami Hiramatsu out:
16595a6f6314SMasami Hiramatsu 	if (map && !is_kprobe) {
16605a6f6314SMasami Hiramatsu 		dso__delete(map->dso);
16615a6f6314SMasami Hiramatsu 		map__delete(map);
16625a6f6314SMasami Hiramatsu 	}
16635a6f6314SMasami Hiramatsu 
16645a6f6314SMasami Hiramatsu 	return ret;
16655a6f6314SMasami Hiramatsu }
16665a6f6314SMasami Hiramatsu 
16675a6f6314SMasami Hiramatsu static int convert_to_perf_probe_point(struct probe_trace_point *tp,
16685a6f6314SMasami Hiramatsu 					struct perf_probe_point *pp,
16695a6f6314SMasami Hiramatsu 					bool is_kprobe)
16705a6f6314SMasami Hiramatsu {
16715a6f6314SMasami Hiramatsu 	char buf[128];
16725a6f6314SMasami Hiramatsu 	int ret;
16735a6f6314SMasami Hiramatsu 
16745a6f6314SMasami Hiramatsu 	ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe);
16755a6f6314SMasami Hiramatsu 	if (!ret)
16765a6f6314SMasami Hiramatsu 		return 0;
16775a6f6314SMasami Hiramatsu 	ret = find_perf_probe_point_from_map(tp, pp, is_kprobe);
16785a6f6314SMasami Hiramatsu 	if (!ret)
16795a6f6314SMasami Hiramatsu 		return 0;
16805a6f6314SMasami Hiramatsu 
16815a6f6314SMasami Hiramatsu 	pr_debug("Failed to find probe point from both of dwarf and map.\n");
16825a6f6314SMasami Hiramatsu 
16835a6f6314SMasami Hiramatsu 	if (tp->symbol) {
16845a6f6314SMasami Hiramatsu 		pp->function = strdup(tp->symbol);
16855a6f6314SMasami Hiramatsu 		pp->offset = tp->offset;
16865a6f6314SMasami Hiramatsu 	} else if (!tp->module && !is_kprobe) {
16875a6f6314SMasami Hiramatsu 		ret = e_snprintf(buf, 128, "0x%" PRIx64, (u64)tp->address);
16885a6f6314SMasami Hiramatsu 		if (ret < 0)
16895a6f6314SMasami Hiramatsu 			return ret;
16905a6f6314SMasami Hiramatsu 		pp->function = strdup(buf);
16915a6f6314SMasami Hiramatsu 		pp->offset = 0;
16925a6f6314SMasami Hiramatsu 	}
16935a6f6314SMasami Hiramatsu 	if (pp->function == NULL)
16945a6f6314SMasami Hiramatsu 		return -ENOMEM;
16955a6f6314SMasami Hiramatsu 
16965a6f6314SMasami Hiramatsu 	pp->retprobe = tp->retprobe;
16975a6f6314SMasami Hiramatsu 
16985a6f6314SMasami Hiramatsu 	return 0;
16995a6f6314SMasami Hiramatsu }
17005a6f6314SMasami Hiramatsu 
17010e60836bSSrikar Dronamraju static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1702225466f1SSrikar Dronamraju 			       struct perf_probe_event *pev, bool is_kprobe)
17034de189feSMasami Hiramatsu {
170402b95dadSMasami Hiramatsu 	char buf[64] = "";
1705146a1439SMasami Hiramatsu 	int i, ret;
17064de189feSMasami Hiramatsu 
17074b4da7f7SMasami Hiramatsu 	/* Convert event/group name */
170802b95dadSMasami Hiramatsu 	pev->event = strdup(tev->event);
170902b95dadSMasami Hiramatsu 	pev->group = strdup(tev->group);
171002b95dadSMasami Hiramatsu 	if (pev->event == NULL || pev->group == NULL)
171102b95dadSMasami Hiramatsu 		return -ENOMEM;
1712fb1587d8SMasami Hiramatsu 
17134b4da7f7SMasami Hiramatsu 	/* Convert trace_point to probe_point */
17145a6f6314SMasami Hiramatsu 	ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe);
1715146a1439SMasami Hiramatsu 	if (ret < 0)
1716146a1439SMasami Hiramatsu 		return ret;
17174b4da7f7SMasami Hiramatsu 
17184235b045SMasami Hiramatsu 	/* Convert trace_arg to probe_arg */
17194235b045SMasami Hiramatsu 	pev->nargs = tev->nargs;
1720e334016fSMasami Hiramatsu 	pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
1721e334016fSMasami Hiramatsu 	if (pev->args == NULL)
1722e334016fSMasami Hiramatsu 		return -ENOMEM;
172302b95dadSMasami Hiramatsu 	for (i = 0; i < tev->nargs && ret >= 0; i++) {
17244235b045SMasami Hiramatsu 		if (tev->args[i].name)
172502b95dadSMasami Hiramatsu 			pev->args[i].name = strdup(tev->args[i].name);
17264235b045SMasami Hiramatsu 		else {
17270e60836bSSrikar Dronamraju 			ret = synthesize_probe_trace_arg(&tev->args[i],
1728146a1439SMasami Hiramatsu 							  buf, 64);
172902b95dadSMasami Hiramatsu 			pev->args[i].name = strdup(buf);
173002b95dadSMasami Hiramatsu 		}
173102b95dadSMasami Hiramatsu 		if (pev->args[i].name == NULL && ret >= 0)
173202b95dadSMasami Hiramatsu 			ret = -ENOMEM;
17334de189feSMasami Hiramatsu 	}
1734146a1439SMasami Hiramatsu 
1735146a1439SMasami Hiramatsu 	if (ret < 0)
1736146a1439SMasami Hiramatsu 		clear_perf_probe_event(pev);
1737146a1439SMasami Hiramatsu 
1738146a1439SMasami Hiramatsu 	return ret;
17394235b045SMasami Hiramatsu }
17404de189feSMasami Hiramatsu 
17414235b045SMasami Hiramatsu void clear_perf_probe_event(struct perf_probe_event *pev)
17424235b045SMasami Hiramatsu {
17434235b045SMasami Hiramatsu 	struct perf_probe_point *pp = &pev->point;
17447df2f329SMasami Hiramatsu 	struct perf_probe_arg_field *field, *next;
17454235b045SMasami Hiramatsu 	int i;
17464de189feSMasami Hiramatsu 
17474235b045SMasami Hiramatsu 	free(pev->event);
17484235b045SMasami Hiramatsu 	free(pev->group);
17494235b045SMasami Hiramatsu 	free(pp->file);
17504235b045SMasami Hiramatsu 	free(pp->function);
17514235b045SMasami Hiramatsu 	free(pp->lazy_line);
1752f5385650SArnaldo Carvalho de Melo 
17537df2f329SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++) {
17544235b045SMasami Hiramatsu 		free(pev->args[i].name);
175548481938SMasami Hiramatsu 		free(pev->args[i].var);
175611a1ca35SMasami Hiramatsu 		free(pev->args[i].type);
17577df2f329SMasami Hiramatsu 		field = pev->args[i].field;
17587df2f329SMasami Hiramatsu 		while (field) {
17597df2f329SMasami Hiramatsu 			next = field->next;
176074cf249dSArnaldo Carvalho de Melo 			zfree(&field->name);
17617df2f329SMasami Hiramatsu 			free(field);
17627df2f329SMasami Hiramatsu 			field = next;
17637df2f329SMasami Hiramatsu 		}
17647df2f329SMasami Hiramatsu 	}
17654235b045SMasami Hiramatsu 	free(pev->args);
17664235b045SMasami Hiramatsu 	memset(pev, 0, sizeof(*pev));
17674235b045SMasami Hiramatsu }
17684235b045SMasami Hiramatsu 
17690e60836bSSrikar Dronamraju static void clear_probe_trace_event(struct probe_trace_event *tev)
17704235b045SMasami Hiramatsu {
17710e60836bSSrikar Dronamraju 	struct probe_trace_arg_ref *ref, *next;
17724235b045SMasami Hiramatsu 	int i;
17734235b045SMasami Hiramatsu 
17744235b045SMasami Hiramatsu 	free(tev->event);
17754235b045SMasami Hiramatsu 	free(tev->group);
17764235b045SMasami Hiramatsu 	free(tev->point.symbol);
1777190b57fcSMasami Hiramatsu 	free(tev->point.module);
17784235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
17794235b045SMasami Hiramatsu 		free(tev->args[i].name);
17804235b045SMasami Hiramatsu 		free(tev->args[i].value);
17814984912eSMasami Hiramatsu 		free(tev->args[i].type);
17824235b045SMasami Hiramatsu 		ref = tev->args[i].ref;
17834235b045SMasami Hiramatsu 		while (ref) {
17844235b045SMasami Hiramatsu 			next = ref->next;
17854235b045SMasami Hiramatsu 			free(ref);
17864235b045SMasami Hiramatsu 			ref = next;
17874235b045SMasami Hiramatsu 		}
17884235b045SMasami Hiramatsu 	}
17894235b045SMasami Hiramatsu 	free(tev->args);
17904235b045SMasami Hiramatsu 	memset(tev, 0, sizeof(*tev));
17914de189feSMasami Hiramatsu }
17924de189feSMasami Hiramatsu 
17935e45187cSMasami Hiramatsu static void print_open_warning(int err, bool is_kprobe)
1794225466f1SSrikar Dronamraju {
17955f03cba4SMasami Hiramatsu 	char sbuf[STRERR_BUFSIZE];
1796225466f1SSrikar Dronamraju 
17975e45187cSMasami Hiramatsu 	if (err == -ENOENT) {
1798225466f1SSrikar Dronamraju 		const char *config;
1799225466f1SSrikar Dronamraju 
1800225466f1SSrikar Dronamraju 		if (!is_kprobe)
1801225466f1SSrikar Dronamraju 			config = "CONFIG_UPROBE_EVENTS";
1802225466f1SSrikar Dronamraju 		else
1803225466f1SSrikar Dronamraju 			config = "CONFIG_KPROBE_EVENTS";
1804225466f1SSrikar Dronamraju 
18055e45187cSMasami Hiramatsu 		pr_warning("%cprobe_events file does not exist"
18065e45187cSMasami Hiramatsu 			   " - please rebuild kernel with %s.\n",
18075e45187cSMasami Hiramatsu 			   is_kprobe ? 'k' : 'u', config);
18085e45187cSMasami Hiramatsu 	} else if (err == -ENOTSUP)
1809*23773ca1SSteven Rostedt (Red Hat) 		pr_warning("Tracefs or debugfs is not mounted.\n");
18105e45187cSMasami Hiramatsu 	else
18115e45187cSMasami Hiramatsu 		pr_warning("Failed to open %cprobe_events: %s\n",
18125e45187cSMasami Hiramatsu 			   is_kprobe ? 'k' : 'u',
18135e45187cSMasami Hiramatsu 			   strerror_r(-err, sbuf, sizeof(sbuf)));
1814225466f1SSrikar Dronamraju }
1815225466f1SSrikar Dronamraju 
1816467ec085SMasami Hiramatsu static void print_both_open_warning(int kerr, int uerr)
1817467ec085SMasami Hiramatsu {
1818467ec085SMasami Hiramatsu 	/* Both kprobes and uprobes are disabled, warn it. */
1819467ec085SMasami Hiramatsu 	if (kerr == -ENOTSUP && uerr == -ENOTSUP)
1820*23773ca1SSteven Rostedt (Red Hat) 		pr_warning("Tracefs or debugfs is not mounted.\n");
1821467ec085SMasami Hiramatsu 	else if (kerr == -ENOENT && uerr == -ENOENT)
1822467ec085SMasami Hiramatsu 		pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS "
1823467ec085SMasami Hiramatsu 			   "or/and CONFIG_UPROBE_EVENTS.\n");
1824467ec085SMasami Hiramatsu 	else {
18255f03cba4SMasami Hiramatsu 		char sbuf[STRERR_BUFSIZE];
1826467ec085SMasami Hiramatsu 		pr_warning("Failed to open kprobe events: %s.\n",
1827467ec085SMasami Hiramatsu 			   strerror_r(-kerr, sbuf, sizeof(sbuf)));
1828467ec085SMasami Hiramatsu 		pr_warning("Failed to open uprobe events: %s.\n",
1829467ec085SMasami Hiramatsu 			   strerror_r(-uerr, sbuf, sizeof(sbuf)));
1830467ec085SMasami Hiramatsu 	}
1831467ec085SMasami Hiramatsu }
1832467ec085SMasami Hiramatsu 
18335e45187cSMasami Hiramatsu static int open_probe_events(const char *trace_file, bool readwrite)
18344de189feSMasami Hiramatsu {
18354de189feSMasami Hiramatsu 	char buf[PATH_MAX];
18367ca5989dSMasami Hiramatsu 	const char *__debugfs;
1837*23773ca1SSteven Rostedt (Red Hat) 	const char *tracing_dir = "";
18384de189feSMasami Hiramatsu 	int ret;
18394de189feSMasami Hiramatsu 
1840*23773ca1SSteven Rostedt (Red Hat) 	__debugfs = tracefs_find_mountpoint();
1841*23773ca1SSteven Rostedt (Red Hat) 	if (__debugfs == NULL) {
1842*23773ca1SSteven Rostedt (Red Hat) 		tracing_dir = "tracing/";
1843*23773ca1SSteven Rostedt (Red Hat) 
18447ca5989dSMasami Hiramatsu 		__debugfs = debugfs_find_mountpoint();
18455e45187cSMasami Hiramatsu 		if (__debugfs == NULL)
18465e45187cSMasami Hiramatsu 			return -ENOTSUP;
1847*23773ca1SSteven Rostedt (Red Hat) 	}
18487ca5989dSMasami Hiramatsu 
1849*23773ca1SSteven Rostedt (Red Hat) 	ret = e_snprintf(buf, PATH_MAX, "%s/%s%s",
1850*23773ca1SSteven Rostedt (Red Hat) 			 __debugfs, tracing_dir, trace_file);
1851146a1439SMasami Hiramatsu 	if (ret >= 0) {
18527ca5989dSMasami Hiramatsu 		pr_debug("Opening %s write=%d\n", buf, readwrite);
1853f4d7da49SMasami Hiramatsu 		if (readwrite && !probe_event_dry_run)
1854f4d7da49SMasami Hiramatsu 			ret = open(buf, O_RDWR, O_APPEND);
1855f4d7da49SMasami Hiramatsu 		else
1856f4d7da49SMasami Hiramatsu 			ret = open(buf, O_RDONLY, 0);
1857f4d7da49SMasami Hiramatsu 
1858225466f1SSrikar Dronamraju 		if (ret < 0)
18595e45187cSMasami Hiramatsu 			ret = -errno;
18604de189feSMasami Hiramatsu 	}
18614de189feSMasami Hiramatsu 	return ret;
18624de189feSMasami Hiramatsu }
18634de189feSMasami Hiramatsu 
1864225466f1SSrikar Dronamraju static int open_kprobe_events(bool readwrite)
1865225466f1SSrikar Dronamraju {
1866*23773ca1SSteven Rostedt (Red Hat) 	return open_probe_events("kprobe_events", readwrite);
1867225466f1SSrikar Dronamraju }
1868225466f1SSrikar Dronamraju 
1869225466f1SSrikar Dronamraju static int open_uprobe_events(bool readwrite)
1870225466f1SSrikar Dronamraju {
1871*23773ca1SSteven Rostedt (Red Hat) 	return open_probe_events("uprobe_events", readwrite);
1872225466f1SSrikar Dronamraju }
1873225466f1SSrikar Dronamraju 
1874225466f1SSrikar Dronamraju /* Get raw string list of current kprobe_events  or uprobe_events */
18750e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_command_rawlist(int fd)
18764de189feSMasami Hiramatsu {
18774de189feSMasami Hiramatsu 	int ret, idx;
18784de189feSMasami Hiramatsu 	FILE *fp;
18794de189feSMasami Hiramatsu 	char buf[MAX_CMDLEN];
18804de189feSMasami Hiramatsu 	char *p;
18814de189feSMasami Hiramatsu 	struct strlist *sl;
18824de189feSMasami Hiramatsu 
18834de189feSMasami Hiramatsu 	sl = strlist__new(true, NULL);
18844de189feSMasami Hiramatsu 
18854de189feSMasami Hiramatsu 	fp = fdopen(dup(fd), "r");
18864de189feSMasami Hiramatsu 	while (!feof(fp)) {
18874de189feSMasami Hiramatsu 		p = fgets(buf, MAX_CMDLEN, fp);
18884de189feSMasami Hiramatsu 		if (!p)
18894de189feSMasami Hiramatsu 			break;
18904de189feSMasami Hiramatsu 
18914de189feSMasami Hiramatsu 		idx = strlen(p) - 1;
18924de189feSMasami Hiramatsu 		if (p[idx] == '\n')
18934de189feSMasami Hiramatsu 			p[idx] = '\0';
18944de189feSMasami Hiramatsu 		ret = strlist__add(sl, buf);
1895146a1439SMasami Hiramatsu 		if (ret < 0) {
18966eb08660SMasami Hiramatsu 			pr_debug("strlist__add failed (%d)\n", ret);
1897146a1439SMasami Hiramatsu 			strlist__delete(sl);
1898146a1439SMasami Hiramatsu 			return NULL;
1899146a1439SMasami Hiramatsu 		}
19004de189feSMasami Hiramatsu 	}
19014de189feSMasami Hiramatsu 	fclose(fp);
19024de189feSMasami Hiramatsu 
19034de189feSMasami Hiramatsu 	return sl;
19044de189feSMasami Hiramatsu }
19054de189feSMasami Hiramatsu 
1906278498d4SMasami Hiramatsu /* Show an event */
1907fb226ccdSMasami Hiramatsu static int show_perf_probe_event(struct perf_probe_event *pev,
1908fb226ccdSMasami Hiramatsu 				 const char *module)
1909278498d4SMasami Hiramatsu {
19107e990a51SMasami Hiramatsu 	int i, ret;
1911278498d4SMasami Hiramatsu 	char buf[128];
19124235b045SMasami Hiramatsu 	char *place;
1913278498d4SMasami Hiramatsu 
19144235b045SMasami Hiramatsu 	/* Synthesize only event probe point */
19154235b045SMasami Hiramatsu 	place = synthesize_perf_probe_point(&pev->point);
1916146a1439SMasami Hiramatsu 	if (!place)
1917146a1439SMasami Hiramatsu 		return -EINVAL;
19184235b045SMasami Hiramatsu 
19194235b045SMasami Hiramatsu 	ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event);
19207e990a51SMasami Hiramatsu 	if (ret < 0)
1921146a1439SMasami Hiramatsu 		return ret;
1922146a1439SMasami Hiramatsu 
19235e17b28fSMasami Hiramatsu 	pr_info("  %-20s (on %s", buf, place);
1924fb226ccdSMasami Hiramatsu 	if (module)
19255e17b28fSMasami Hiramatsu 		pr_info(" in %s", module);
1926278498d4SMasami Hiramatsu 
19274235b045SMasami Hiramatsu 	if (pev->nargs > 0) {
19285e17b28fSMasami Hiramatsu 		pr_info(" with");
19297df2f329SMasami Hiramatsu 		for (i = 0; i < pev->nargs; i++) {
1930146a1439SMasami Hiramatsu 			ret = synthesize_perf_probe_arg(&pev->args[i],
1931146a1439SMasami Hiramatsu 							buf, 128);
1932146a1439SMasami Hiramatsu 			if (ret < 0)
1933146a1439SMasami Hiramatsu 				break;
19345e17b28fSMasami Hiramatsu 			pr_info(" %s", buf);
19357df2f329SMasami Hiramatsu 		}
1936278498d4SMasami Hiramatsu 	}
19375e17b28fSMasami Hiramatsu 	pr_info(")\n");
19384235b045SMasami Hiramatsu 	free(place);
1939146a1439SMasami Hiramatsu 	return ret;
1940278498d4SMasami Hiramatsu }
1941278498d4SMasami Hiramatsu 
1942225466f1SSrikar Dronamraju static int __show_perf_probe_events(int fd, bool is_kprobe)
19434de189feSMasami Hiramatsu {
1944225466f1SSrikar Dronamraju 	int ret = 0;
19450e60836bSSrikar Dronamraju 	struct probe_trace_event tev;
19464235b045SMasami Hiramatsu 	struct perf_probe_event pev;
19474de189feSMasami Hiramatsu 	struct strlist *rawlist;
19484de189feSMasami Hiramatsu 	struct str_node *ent;
19494de189feSMasami Hiramatsu 
19504235b045SMasami Hiramatsu 	memset(&tev, 0, sizeof(tev));
19514235b045SMasami Hiramatsu 	memset(&pev, 0, sizeof(pev));
195272041334SMasami Hiramatsu 
19530e60836bSSrikar Dronamraju 	rawlist = get_probe_trace_command_rawlist(fd);
1954146a1439SMasami Hiramatsu 	if (!rawlist)
19556eb08660SMasami Hiramatsu 		return -ENOMEM;
19564de189feSMasami Hiramatsu 
1957adf365f4SMasami Hiramatsu 	strlist__for_each(ent, rawlist) {
19580e60836bSSrikar Dronamraju 		ret = parse_probe_trace_command(ent->s, &tev);
1959146a1439SMasami Hiramatsu 		if (ret >= 0) {
1960225466f1SSrikar Dronamraju 			ret = convert_to_perf_probe_event(&tev, &pev,
1961225466f1SSrikar Dronamraju 								is_kprobe);
1962146a1439SMasami Hiramatsu 			if (ret >= 0)
1963fb226ccdSMasami Hiramatsu 				ret = show_perf_probe_event(&pev,
1964fb226ccdSMasami Hiramatsu 							    tev.point.module);
1965146a1439SMasami Hiramatsu 		}
19664235b045SMasami Hiramatsu 		clear_perf_probe_event(&pev);
19670e60836bSSrikar Dronamraju 		clear_probe_trace_event(&tev);
1968146a1439SMasami Hiramatsu 		if (ret < 0)
1969146a1439SMasami Hiramatsu 			break;
19704de189feSMasami Hiramatsu 	}
19714de189feSMasami Hiramatsu 	strlist__delete(rawlist);
1972146a1439SMasami Hiramatsu 
1973146a1439SMasami Hiramatsu 	return ret;
19744de189feSMasami Hiramatsu }
19754de189feSMasami Hiramatsu 
1976225466f1SSrikar Dronamraju /* List up current perf-probe events */
1977225466f1SSrikar Dronamraju int show_perf_probe_events(void)
1978225466f1SSrikar Dronamraju {
19795e45187cSMasami Hiramatsu 	int kp_fd, up_fd, ret;
1980225466f1SSrikar Dronamraju 
1981225466f1SSrikar Dronamraju 	setup_pager();
1982225466f1SSrikar Dronamraju 
1983ee45b6c2SMasami Hiramatsu 	ret = init_symbol_maps(false);
1984225466f1SSrikar Dronamraju 	if (ret < 0)
1985225466f1SSrikar Dronamraju 		return ret;
1986225466f1SSrikar Dronamraju 
19875e45187cSMasami Hiramatsu 	kp_fd = open_kprobe_events(false);
19885e45187cSMasami Hiramatsu 	if (kp_fd >= 0) {
19895e45187cSMasami Hiramatsu 		ret = __show_perf_probe_events(kp_fd, true);
19905e45187cSMasami Hiramatsu 		close(kp_fd);
19915e45187cSMasami Hiramatsu 		if (ret < 0)
19925e45187cSMasami Hiramatsu 			goto out;
1993225466f1SSrikar Dronamraju 	}
1994225466f1SSrikar Dronamraju 
19955e45187cSMasami Hiramatsu 	up_fd = open_uprobe_events(false);
19965e45187cSMasami Hiramatsu 	if (kp_fd < 0 && up_fd < 0) {
1997467ec085SMasami Hiramatsu 		print_both_open_warning(kp_fd, up_fd);
19985e45187cSMasami Hiramatsu 		ret = kp_fd;
19995e45187cSMasami Hiramatsu 		goto out;
20005e45187cSMasami Hiramatsu 	}
20015e45187cSMasami Hiramatsu 
20025e45187cSMasami Hiramatsu 	if (up_fd >= 0) {
20035e45187cSMasami Hiramatsu 		ret = __show_perf_probe_events(up_fd, false);
20045e45187cSMasami Hiramatsu 		close(up_fd);
20055e45187cSMasami Hiramatsu 	}
20065e45187cSMasami Hiramatsu out:
2007ee45b6c2SMasami Hiramatsu 	exit_symbol_maps();
2008225466f1SSrikar Dronamraju 	return ret;
2009225466f1SSrikar Dronamraju }
2010225466f1SSrikar Dronamraju 
2011b498ce1fSMasami Hiramatsu /* Get current perf-probe event names */
20120e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
2013b498ce1fSMasami Hiramatsu {
2014fa28244dSMasami Hiramatsu 	char buf[128];
2015b498ce1fSMasami Hiramatsu 	struct strlist *sl, *rawlist;
2016b498ce1fSMasami Hiramatsu 	struct str_node *ent;
20170e60836bSSrikar Dronamraju 	struct probe_trace_event tev;
2018146a1439SMasami Hiramatsu 	int ret = 0;
2019b498ce1fSMasami Hiramatsu 
20204235b045SMasami Hiramatsu 	memset(&tev, 0, sizeof(tev));
20210e60836bSSrikar Dronamraju 	rawlist = get_probe_trace_command_rawlist(fd);
20226eb08660SMasami Hiramatsu 	if (!rawlist)
20236eb08660SMasami Hiramatsu 		return NULL;
2024e1d2017bSMasami Hiramatsu 	sl = strlist__new(true, NULL);
2025adf365f4SMasami Hiramatsu 	strlist__for_each(ent, rawlist) {
20260e60836bSSrikar Dronamraju 		ret = parse_probe_trace_command(ent->s, &tev);
2027146a1439SMasami Hiramatsu 		if (ret < 0)
2028146a1439SMasami Hiramatsu 			break;
2029fa28244dSMasami Hiramatsu 		if (include_group) {
2030146a1439SMasami Hiramatsu 			ret = e_snprintf(buf, 128, "%s:%s", tev.group,
2031146a1439SMasami Hiramatsu 					tev.event);
2032146a1439SMasami Hiramatsu 			if (ret >= 0)
2033146a1439SMasami Hiramatsu 				ret = strlist__add(sl, buf);
2034fa28244dSMasami Hiramatsu 		} else
2035146a1439SMasami Hiramatsu 			ret = strlist__add(sl, tev.event);
20360e60836bSSrikar Dronamraju 		clear_probe_trace_event(&tev);
2037146a1439SMasami Hiramatsu 		if (ret < 0)
2038146a1439SMasami Hiramatsu 			break;
2039b498ce1fSMasami Hiramatsu 	}
2040b498ce1fSMasami Hiramatsu 	strlist__delete(rawlist);
2041b498ce1fSMasami Hiramatsu 
2042146a1439SMasami Hiramatsu 	if (ret < 0) {
2043146a1439SMasami Hiramatsu 		strlist__delete(sl);
2044146a1439SMasami Hiramatsu 		return NULL;
2045146a1439SMasami Hiramatsu 	}
2046b498ce1fSMasami Hiramatsu 	return sl;
2047b498ce1fSMasami Hiramatsu }
2048b498ce1fSMasami Hiramatsu 
20490e60836bSSrikar Dronamraju static int write_probe_trace_event(int fd, struct probe_trace_event *tev)
205050656eecSMasami Hiramatsu {
20516eca8cc3SFrederic Weisbecker 	int ret = 0;
20520e60836bSSrikar Dronamraju 	char *buf = synthesize_probe_trace_command(tev);
20535f03cba4SMasami Hiramatsu 	char sbuf[STRERR_BUFSIZE];
205450656eecSMasami Hiramatsu 
2055146a1439SMasami Hiramatsu 	if (!buf) {
20560e60836bSSrikar Dronamraju 		pr_debug("Failed to synthesize probe trace event.\n");
2057146a1439SMasami Hiramatsu 		return -EINVAL;
2058146a1439SMasami Hiramatsu 	}
2059146a1439SMasami Hiramatsu 
2060fa28244dSMasami Hiramatsu 	pr_debug("Writing event: %s\n", buf);
2061f4d7da49SMasami Hiramatsu 	if (!probe_event_dry_run) {
206250656eecSMasami Hiramatsu 		ret = write(fd, buf, strlen(buf));
20637949ba1fSNamhyung Kim 		if (ret <= 0) {
20647949ba1fSNamhyung Kim 			ret = -errno;
2065146a1439SMasami Hiramatsu 			pr_warning("Failed to write event: %s\n",
20665f03cba4SMasami Hiramatsu 				   strerror_r(errno, sbuf, sizeof(sbuf)));
206750656eecSMasami Hiramatsu 		}
20687949ba1fSNamhyung Kim 	}
20694235b045SMasami Hiramatsu 	free(buf);
2070146a1439SMasami Hiramatsu 	return ret;
2071f4d7da49SMasami Hiramatsu }
207250656eecSMasami Hiramatsu 
2073146a1439SMasami Hiramatsu static int get_new_event_name(char *buf, size_t len, const char *base,
2074d761b08bSMasami Hiramatsu 			      struct strlist *namelist, bool allow_suffix)
2075b498ce1fSMasami Hiramatsu {
2076b498ce1fSMasami Hiramatsu 	int i, ret;
207717f88fcdSMasami Hiramatsu 
207817f88fcdSMasami Hiramatsu 	/* Try no suffix */
207917f88fcdSMasami Hiramatsu 	ret = e_snprintf(buf, len, "%s", base);
2080146a1439SMasami Hiramatsu 	if (ret < 0) {
20815f03cba4SMasami Hiramatsu 		pr_debug("snprintf() failed: %d\n", ret);
2082146a1439SMasami Hiramatsu 		return ret;
2083146a1439SMasami Hiramatsu 	}
208417f88fcdSMasami Hiramatsu 	if (!strlist__has_entry(namelist, buf))
2085146a1439SMasami Hiramatsu 		return 0;
208617f88fcdSMasami Hiramatsu 
2087d761b08bSMasami Hiramatsu 	if (!allow_suffix) {
2088d761b08bSMasami Hiramatsu 		pr_warning("Error: event \"%s\" already exists. "
2089d761b08bSMasami Hiramatsu 			   "(Use -f to force duplicates.)\n", base);
2090146a1439SMasami Hiramatsu 		return -EEXIST;
2091d761b08bSMasami Hiramatsu 	}
2092d761b08bSMasami Hiramatsu 
209317f88fcdSMasami Hiramatsu 	/* Try to add suffix */
209417f88fcdSMasami Hiramatsu 	for (i = 1; i < MAX_EVENT_INDEX; i++) {
2095b498ce1fSMasami Hiramatsu 		ret = e_snprintf(buf, len, "%s_%d", base, i);
2096146a1439SMasami Hiramatsu 		if (ret < 0) {
20975f03cba4SMasami Hiramatsu 			pr_debug("snprintf() failed: %d\n", ret);
2098146a1439SMasami Hiramatsu 			return ret;
2099146a1439SMasami Hiramatsu 		}
2100b498ce1fSMasami Hiramatsu 		if (!strlist__has_entry(namelist, buf))
2101b498ce1fSMasami Hiramatsu 			break;
2102b498ce1fSMasami Hiramatsu 	}
2103146a1439SMasami Hiramatsu 	if (i == MAX_EVENT_INDEX) {
2104146a1439SMasami Hiramatsu 		pr_warning("Too many events are on the same function.\n");
2105146a1439SMasami Hiramatsu 		ret = -ERANGE;
2106b498ce1fSMasami Hiramatsu 	}
2107b498ce1fSMasami Hiramatsu 
2108146a1439SMasami Hiramatsu 	return ret;
2109146a1439SMasami Hiramatsu }
2110146a1439SMasami Hiramatsu 
21110e60836bSSrikar Dronamraju static int __add_probe_trace_events(struct perf_probe_event *pev,
21120e60836bSSrikar Dronamraju 				     struct probe_trace_event *tevs,
21134235b045SMasami Hiramatsu 				     int ntevs, bool allow_suffix)
211450656eecSMasami Hiramatsu {
2115146a1439SMasami Hiramatsu 	int i, fd, ret;
21160e60836bSSrikar Dronamraju 	struct probe_trace_event *tev = NULL;
21174235b045SMasami Hiramatsu 	char buf[64];
21184235b045SMasami Hiramatsu 	const char *event, *group;
2119b498ce1fSMasami Hiramatsu 	struct strlist *namelist;
212050656eecSMasami Hiramatsu 
2121225466f1SSrikar Dronamraju 	if (pev->uprobes)
2122225466f1SSrikar Dronamraju 		fd = open_uprobe_events(true);
2123225466f1SSrikar Dronamraju 	else
2124f4d7da49SMasami Hiramatsu 		fd = open_kprobe_events(true);
2125225466f1SSrikar Dronamraju 
21265e45187cSMasami Hiramatsu 	if (fd < 0) {
21275e45187cSMasami Hiramatsu 		print_open_warning(fd, !pev->uprobes);
2128146a1439SMasami Hiramatsu 		return fd;
21295e45187cSMasami Hiramatsu 	}
21305e45187cSMasami Hiramatsu 
2131b498ce1fSMasami Hiramatsu 	/* Get current event names */
21320e60836bSSrikar Dronamraju 	namelist = get_probe_trace_event_names(fd, false);
2133146a1439SMasami Hiramatsu 	if (!namelist) {
2134146a1439SMasami Hiramatsu 		pr_debug("Failed to get current event list.\n");
2135146a1439SMasami Hiramatsu 		return -EIO;
2136146a1439SMasami Hiramatsu 	}
213750656eecSMasami Hiramatsu 
2138146a1439SMasami Hiramatsu 	ret = 0;
21395e17b28fSMasami Hiramatsu 	pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
214002b95dadSMasami Hiramatsu 	for (i = 0; i < ntevs; i++) {
21414235b045SMasami Hiramatsu 		tev = &tevs[i];
21424235b045SMasami Hiramatsu 		if (pev->event)
21434235b045SMasami Hiramatsu 			event = pev->event;
21444235b045SMasami Hiramatsu 		else
21454235b045SMasami Hiramatsu 			if (pev->point.function)
21464235b045SMasami Hiramatsu 				event = pev->point.function;
21474235b045SMasami Hiramatsu 			else
21484235b045SMasami Hiramatsu 				event = tev->point.symbol;
21494235b045SMasami Hiramatsu 		if (pev->group)
21504235b045SMasami Hiramatsu 			group = pev->group;
21514235b045SMasami Hiramatsu 		else
21524235b045SMasami Hiramatsu 			group = PERFPROBE_GROUP;
21534235b045SMasami Hiramatsu 
2154b498ce1fSMasami Hiramatsu 		/* Get an unused new event name */
2155146a1439SMasami Hiramatsu 		ret = get_new_event_name(buf, 64, event,
2156146a1439SMasami Hiramatsu 					 namelist, allow_suffix);
2157146a1439SMasami Hiramatsu 		if (ret < 0)
2158146a1439SMasami Hiramatsu 			break;
21594235b045SMasami Hiramatsu 		event = buf;
21604235b045SMasami Hiramatsu 
216102b95dadSMasami Hiramatsu 		tev->event = strdup(event);
216202b95dadSMasami Hiramatsu 		tev->group = strdup(group);
216302b95dadSMasami Hiramatsu 		if (tev->event == NULL || tev->group == NULL) {
216402b95dadSMasami Hiramatsu 			ret = -ENOMEM;
216502b95dadSMasami Hiramatsu 			break;
216602b95dadSMasami Hiramatsu 		}
21670e60836bSSrikar Dronamraju 		ret = write_probe_trace_event(fd, tev);
2168146a1439SMasami Hiramatsu 		if (ret < 0)
2169146a1439SMasami Hiramatsu 			break;
2170b498ce1fSMasami Hiramatsu 		/* Add added event name to namelist */
2171b498ce1fSMasami Hiramatsu 		strlist__add(namelist, event);
21724235b045SMasami Hiramatsu 
21734235b045SMasami Hiramatsu 		/* Trick here - save current event/group */
21744235b045SMasami Hiramatsu 		event = pev->event;
21754235b045SMasami Hiramatsu 		group = pev->group;
21764235b045SMasami Hiramatsu 		pev->event = tev->event;
21774235b045SMasami Hiramatsu 		pev->group = tev->group;
2178fb226ccdSMasami Hiramatsu 		show_perf_probe_event(pev, tev->point.module);
21794235b045SMasami Hiramatsu 		/* Trick here - restore current event/group */
21804235b045SMasami Hiramatsu 		pev->event = (char *)event;
21814235b045SMasami Hiramatsu 		pev->group = (char *)group;
21824235b045SMasami Hiramatsu 
2183d761b08bSMasami Hiramatsu 		/*
2184d761b08bSMasami Hiramatsu 		 * Probes after the first probe which comes from same
2185d761b08bSMasami Hiramatsu 		 * user input are always allowed to add suffix, because
2186d761b08bSMasami Hiramatsu 		 * there might be several addresses corresponding to
2187d761b08bSMasami Hiramatsu 		 * one code line.
2188d761b08bSMasami Hiramatsu 		 */
2189d761b08bSMasami Hiramatsu 		allow_suffix = true;
219050656eecSMasami Hiramatsu 	}
2191146a1439SMasami Hiramatsu 
2192146a1439SMasami Hiramatsu 	if (ret >= 0) {
2193a9b495b0SMasami Hiramatsu 		/* Show how to use the event. */
21945e17b28fSMasami Hiramatsu 		pr_info("\nYou can now use it in all perf tools, such as:\n\n");
21955e17b28fSMasami Hiramatsu 		pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
2196146a1439SMasami Hiramatsu 			 tev->event);
2197146a1439SMasami Hiramatsu 	}
2198a9b495b0SMasami Hiramatsu 
2199e1d2017bSMasami Hiramatsu 	strlist__delete(namelist);
220050656eecSMasami Hiramatsu 	close(fd);
2201146a1439SMasami Hiramatsu 	return ret;
220250656eecSMasami Hiramatsu }
2203fa28244dSMasami Hiramatsu 
2204564c62a4SNamhyung Kim static int find_probe_functions(struct map *map, char *name)
2205eb948e50SMasami Hiramatsu {
2206564c62a4SNamhyung Kim 	int found = 0;
22070a3873a8SArnaldo Carvalho de Melo 	struct symbol *sym;
2208564c62a4SNamhyung Kim 
22090a3873a8SArnaldo Carvalho de Melo 	map__for_each_symbol_by_name(map, name, sym) {
2210564c62a4SNamhyung Kim 		if (sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL)
2211564c62a4SNamhyung Kim 			found++;
2212eb948e50SMasami Hiramatsu 	}
2213564c62a4SNamhyung Kim 
2214564c62a4SNamhyung Kim 	return found;
2215eb948e50SMasami Hiramatsu }
2216eb948e50SMasami Hiramatsu 
2217eb948e50SMasami Hiramatsu #define strdup_or_goto(str, label)	\
2218eb948e50SMasami Hiramatsu 	({ char *__p = strdup(str); if (!__p) goto label; __p; })
2219eb948e50SMasami Hiramatsu 
2220eb948e50SMasami Hiramatsu /*
2221eb948e50SMasami Hiramatsu  * Find probe function addresses from map.
2222eb948e50SMasami Hiramatsu  * Return an error or the number of found probe_trace_event
2223eb948e50SMasami Hiramatsu  */
2224eb948e50SMasami Hiramatsu static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
2225eb948e50SMasami Hiramatsu 					    struct probe_trace_event **tevs,
2226eb948e50SMasami Hiramatsu 					    int max_tevs, const char *target)
2227eb948e50SMasami Hiramatsu {
2228eb948e50SMasami Hiramatsu 	struct map *map = NULL;
2229eb948e50SMasami Hiramatsu 	struct kmap *kmap = NULL;
2230eb948e50SMasami Hiramatsu 	struct ref_reloc_sym *reloc_sym = NULL;
2231eb948e50SMasami Hiramatsu 	struct symbol *sym;
2232eb948e50SMasami Hiramatsu 	struct probe_trace_event *tev;
2233eb948e50SMasami Hiramatsu 	struct perf_probe_point *pp = &pev->point;
2234eb948e50SMasami Hiramatsu 	struct probe_trace_point *tp;
2235564c62a4SNamhyung Kim 	int num_matched_functions;
2236eb948e50SMasami Hiramatsu 	int ret, i;
2237eb948e50SMasami Hiramatsu 
2238eb948e50SMasami Hiramatsu 	/* Init maps of given executable or kernel */
2239eb948e50SMasami Hiramatsu 	if (pev->uprobes)
2240eb948e50SMasami Hiramatsu 		map = dso__new_map(target);
2241eb948e50SMasami Hiramatsu 	else
2242eb948e50SMasami Hiramatsu 		map = kernel_get_module_map(target);
2243eb948e50SMasami Hiramatsu 	if (!map) {
2244eb948e50SMasami Hiramatsu 		ret = -EINVAL;
2245eb948e50SMasami Hiramatsu 		goto out;
2246eb948e50SMasami Hiramatsu 	}
2247eb948e50SMasami Hiramatsu 
2248eb948e50SMasami Hiramatsu 	/*
2249eb948e50SMasami Hiramatsu 	 * Load matched symbols: Since the different local symbols may have
2250eb948e50SMasami Hiramatsu 	 * same name but different addresses, this lists all the symbols.
2251eb948e50SMasami Hiramatsu 	 */
2252564c62a4SNamhyung Kim 	num_matched_functions = find_probe_functions(map, pp->function);
2253564c62a4SNamhyung Kim 	if (num_matched_functions == 0) {
2254eb948e50SMasami Hiramatsu 		pr_err("Failed to find symbol %s in %s\n", pp->function,
2255eb948e50SMasami Hiramatsu 			target ? : "kernel");
2256eb948e50SMasami Hiramatsu 		ret = -ENOENT;
2257eb948e50SMasami Hiramatsu 		goto out;
2258eb948e50SMasami Hiramatsu 	} else if (num_matched_functions > max_tevs) {
2259eb948e50SMasami Hiramatsu 		pr_err("Too many functions matched in %s\n",
2260eb948e50SMasami Hiramatsu 			target ? : "kernel");
2261eb948e50SMasami Hiramatsu 		ret = -E2BIG;
2262eb948e50SMasami Hiramatsu 		goto out;
2263eb948e50SMasami Hiramatsu 	}
2264eb948e50SMasami Hiramatsu 
226525dd9171SNamhyung Kim 	if (!pev->uprobes && !pp->retprobe) {
2266eb948e50SMasami Hiramatsu 		kmap = map__kmap(map);
2267eb948e50SMasami Hiramatsu 		reloc_sym = kmap->ref_reloc_sym;
2268eb948e50SMasami Hiramatsu 		if (!reloc_sym) {
2269eb948e50SMasami Hiramatsu 			pr_warning("Relocated base symbol is not found!\n");
2270eb948e50SMasami Hiramatsu 			ret = -EINVAL;
2271eb948e50SMasami Hiramatsu 			goto out;
2272eb948e50SMasami Hiramatsu 		}
2273eb948e50SMasami Hiramatsu 	}
2274eb948e50SMasami Hiramatsu 
2275eb948e50SMasami Hiramatsu 	/* Setup result trace-probe-events */
2276eb948e50SMasami Hiramatsu 	*tevs = zalloc(sizeof(*tev) * num_matched_functions);
2277eb948e50SMasami Hiramatsu 	if (!*tevs) {
2278eb948e50SMasami Hiramatsu 		ret = -ENOMEM;
2279eb948e50SMasami Hiramatsu 		goto out;
2280eb948e50SMasami Hiramatsu 	}
2281eb948e50SMasami Hiramatsu 
2282eb948e50SMasami Hiramatsu 	ret = 0;
2283564c62a4SNamhyung Kim 
22840a3873a8SArnaldo Carvalho de Melo 	map__for_each_symbol_by_name(map, pp->function, sym) {
2285eb948e50SMasami Hiramatsu 		tev = (*tevs) + ret;
2286eb948e50SMasami Hiramatsu 		tp = &tev->point;
2287eb948e50SMasami Hiramatsu 		if (ret == num_matched_functions) {
2288eb948e50SMasami Hiramatsu 			pr_warning("Too many symbols are listed. Skip it.\n");
2289eb948e50SMasami Hiramatsu 			break;
2290eb948e50SMasami Hiramatsu 		}
2291eb948e50SMasami Hiramatsu 		ret++;
2292eb948e50SMasami Hiramatsu 
2293eb948e50SMasami Hiramatsu 		if (pp->offset > sym->end - sym->start) {
2294eb948e50SMasami Hiramatsu 			pr_warning("Offset %ld is bigger than the size of %s\n",
2295eb948e50SMasami Hiramatsu 				   pp->offset, sym->name);
2296eb948e50SMasami Hiramatsu 			ret = -ENOENT;
2297eb948e50SMasami Hiramatsu 			goto err_out;
2298eb948e50SMasami Hiramatsu 		}
2299eb948e50SMasami Hiramatsu 		/* Add one probe point */
2300eb948e50SMasami Hiramatsu 		tp->address = map->unmap_ip(map, sym->start) + pp->offset;
2301eb948e50SMasami Hiramatsu 		if (reloc_sym) {
2302eb948e50SMasami Hiramatsu 			tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out);
2303eb948e50SMasami Hiramatsu 			tp->offset = tp->address - reloc_sym->addr;
2304eb948e50SMasami Hiramatsu 		} else {
2305eb948e50SMasami Hiramatsu 			tp->symbol = strdup_or_goto(sym->name, nomem_out);
2306eb948e50SMasami Hiramatsu 			tp->offset = pp->offset;
2307eb948e50SMasami Hiramatsu 		}
2308eb948e50SMasami Hiramatsu 		tp->retprobe = pp->retprobe;
2309eb948e50SMasami Hiramatsu 		if (target)
2310eb948e50SMasami Hiramatsu 			tev->point.module = strdup_or_goto(target, nomem_out);
2311eb948e50SMasami Hiramatsu 		tev->uprobes = pev->uprobes;
2312eb948e50SMasami Hiramatsu 		tev->nargs = pev->nargs;
2313eb948e50SMasami Hiramatsu 		if (tev->nargs) {
2314eb948e50SMasami Hiramatsu 			tev->args = zalloc(sizeof(struct probe_trace_arg) *
2315eb948e50SMasami Hiramatsu 					   tev->nargs);
2316eb948e50SMasami Hiramatsu 			if (tev->args == NULL)
2317eb948e50SMasami Hiramatsu 				goto nomem_out;
2318eb948e50SMasami Hiramatsu 		}
2319eb948e50SMasami Hiramatsu 		for (i = 0; i < tev->nargs; i++) {
2320eb948e50SMasami Hiramatsu 			if (pev->args[i].name)
2321eb948e50SMasami Hiramatsu 				tev->args[i].name =
2322eb948e50SMasami Hiramatsu 					strdup_or_goto(pev->args[i].name,
2323eb948e50SMasami Hiramatsu 							nomem_out);
2324eb948e50SMasami Hiramatsu 
2325eb948e50SMasami Hiramatsu 			tev->args[i].value = strdup_or_goto(pev->args[i].var,
2326eb948e50SMasami Hiramatsu 							    nomem_out);
2327eb948e50SMasami Hiramatsu 			if (pev->args[i].type)
2328eb948e50SMasami Hiramatsu 				tev->args[i].type =
2329eb948e50SMasami Hiramatsu 					strdup_or_goto(pev->args[i].type,
2330eb948e50SMasami Hiramatsu 							nomem_out);
2331eb948e50SMasami Hiramatsu 		}
2332eb948e50SMasami Hiramatsu 	}
2333eb948e50SMasami Hiramatsu 
2334eb948e50SMasami Hiramatsu out:
2335eb948e50SMasami Hiramatsu 	if (map && pev->uprobes) {
2336eb948e50SMasami Hiramatsu 		/* Only when using uprobe(exec) map needs to be released */
2337eb948e50SMasami Hiramatsu 		dso__delete(map->dso);
2338eb948e50SMasami Hiramatsu 		map__delete(map);
2339eb948e50SMasami Hiramatsu 	}
2340eb948e50SMasami Hiramatsu 	return ret;
2341eb948e50SMasami Hiramatsu 
2342eb948e50SMasami Hiramatsu nomem_out:
2343eb948e50SMasami Hiramatsu 	ret = -ENOMEM;
2344eb948e50SMasami Hiramatsu err_out:
2345eb948e50SMasami Hiramatsu 	clear_probe_trace_events(*tevs, num_matched_functions);
2346eb948e50SMasami Hiramatsu 	zfree(tevs);
2347eb948e50SMasami Hiramatsu 	goto out;
2348eb948e50SMasami Hiramatsu }
2349eb948e50SMasami Hiramatsu 
23500e60836bSSrikar Dronamraju static int convert_to_probe_trace_events(struct perf_probe_event *pev,
23510e60836bSSrikar Dronamraju 					  struct probe_trace_event **tevs,
23524eced234SSrikar Dronamraju 					  int max_tevs, const char *target)
2353e0faa8d3SMasami Hiramatsu {
2354eb948e50SMasami Hiramatsu 	int ret;
23554235b045SMasami Hiramatsu 
2356fb7345bbSMasami Hiramatsu 	if (pev->uprobes && !pev->group) {
2357fb7345bbSMasami Hiramatsu 		/* Replace group name if not given */
2358fb7345bbSMasami Hiramatsu 		ret = convert_exec_to_group(target, &pev->group);
2359fb7345bbSMasami Hiramatsu 		if (ret != 0) {
2360fb7345bbSMasami Hiramatsu 			pr_warning("Failed to make a group name.\n");
2361fb7345bbSMasami Hiramatsu 			return ret;
2362fb7345bbSMasami Hiramatsu 		}
2363fb7345bbSMasami Hiramatsu 	}
2364fb7345bbSMasami Hiramatsu 
23654b4da7f7SMasami Hiramatsu 	/* Convert perf_probe_event with debuginfo */
23664eced234SSrikar Dronamraju 	ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target);
2367e334016fSMasami Hiramatsu 	if (ret != 0)
2368190b57fcSMasami Hiramatsu 		return ret;	/* Found in debuginfo or got an error */
2369e0faa8d3SMasami Hiramatsu 
2370eb948e50SMasami Hiramatsu 	return find_probe_trace_events_from_map(pev, tevs, max_tevs, target);
23714235b045SMasami Hiramatsu }
23724235b045SMasami Hiramatsu 
23734235b045SMasami Hiramatsu struct __event_package {
23744235b045SMasami Hiramatsu 	struct perf_probe_event		*pev;
23750e60836bSSrikar Dronamraju 	struct probe_trace_event	*tevs;
23764235b045SMasami Hiramatsu 	int				ntevs;
23774235b045SMasami Hiramatsu };
23784235b045SMasami Hiramatsu 
2379146a1439SMasami Hiramatsu int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
23804eced234SSrikar Dronamraju 			  int max_tevs, const char *target, bool force_add)
23814235b045SMasami Hiramatsu {
2382146a1439SMasami Hiramatsu 	int i, j, ret;
23834235b045SMasami Hiramatsu 	struct __event_package *pkgs;
23844235b045SMasami Hiramatsu 
2385225466f1SSrikar Dronamraju 	ret = 0;
2386e334016fSMasami Hiramatsu 	pkgs = zalloc(sizeof(struct __event_package) * npevs);
2387225466f1SSrikar Dronamraju 
2388e334016fSMasami Hiramatsu 	if (pkgs == NULL)
2389e334016fSMasami Hiramatsu 		return -ENOMEM;
23904235b045SMasami Hiramatsu 
2391ee45b6c2SMasami Hiramatsu 	ret = init_symbol_maps(pevs->uprobes);
2392449e5b24SMasami Hiramatsu 	if (ret < 0) {
2393449e5b24SMasami Hiramatsu 		free(pkgs);
2394146a1439SMasami Hiramatsu 		return ret;
2395449e5b24SMasami Hiramatsu 	}
23964235b045SMasami Hiramatsu 
23974235b045SMasami Hiramatsu 	/* Loop 1: convert all events */
23984235b045SMasami Hiramatsu 	for (i = 0; i < npevs; i++) {
23994235b045SMasami Hiramatsu 		pkgs[i].pev = &pevs[i];
24004235b045SMasami Hiramatsu 		/* Convert with or without debuginfo */
24010e60836bSSrikar Dronamraju 		ret  = convert_to_probe_trace_events(pkgs[i].pev,
2402469b9b88SMasami Hiramatsu 						     &pkgs[i].tevs,
2403469b9b88SMasami Hiramatsu 						     max_tevs,
24044eced234SSrikar Dronamraju 						     target);
2405146a1439SMasami Hiramatsu 		if (ret < 0)
2406146a1439SMasami Hiramatsu 			goto end;
2407146a1439SMasami Hiramatsu 		pkgs[i].ntevs = ret;
24084235b045SMasami Hiramatsu 	}
24094235b045SMasami Hiramatsu 
24104235b045SMasami Hiramatsu 	/* Loop 2: add all events */
24118635bf6eSArnaldo Carvalho de Melo 	for (i = 0; i < npevs; i++) {
24120e60836bSSrikar Dronamraju 		ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs,
24134235b045SMasami Hiramatsu 						pkgs[i].ntevs, force_add);
2414fbee632dSArnaldo Carvalho de Melo 		if (ret < 0)
2415fbee632dSArnaldo Carvalho de Melo 			break;
2416fbee632dSArnaldo Carvalho de Melo 	}
2417146a1439SMasami Hiramatsu end:
2418449e5b24SMasami Hiramatsu 	/* Loop 3: cleanup and free trace events  */
2419449e5b24SMasami Hiramatsu 	for (i = 0; i < npevs; i++) {
2420146a1439SMasami Hiramatsu 		for (j = 0; j < pkgs[i].ntevs; j++)
24210e60836bSSrikar Dronamraju 			clear_probe_trace_event(&pkgs[i].tevs[j]);
242274cf249dSArnaldo Carvalho de Melo 		zfree(&pkgs[i].tevs);
2423449e5b24SMasami Hiramatsu 	}
2424449e5b24SMasami Hiramatsu 	free(pkgs);
2425ee45b6c2SMasami Hiramatsu 	exit_symbol_maps();
2426146a1439SMasami Hiramatsu 
2427146a1439SMasami Hiramatsu 	return ret;
2428e0faa8d3SMasami Hiramatsu }
2429e0faa8d3SMasami Hiramatsu 
24300e60836bSSrikar Dronamraju static int __del_trace_probe_event(int fd, struct str_node *ent)
2431bbbb521bSMasami Hiramatsu {
2432bbbb521bSMasami Hiramatsu 	char *p;
2433bbbb521bSMasami Hiramatsu 	char buf[128];
24344235b045SMasami Hiramatsu 	int ret;
2435bbbb521bSMasami Hiramatsu 
24360e60836bSSrikar Dronamraju 	/* Convert from perf-probe event to trace-probe event */
2437146a1439SMasami Hiramatsu 	ret = e_snprintf(buf, 128, "-:%s", ent->s);
2438146a1439SMasami Hiramatsu 	if (ret < 0)
2439146a1439SMasami Hiramatsu 		goto error;
2440146a1439SMasami Hiramatsu 
2441bbbb521bSMasami Hiramatsu 	p = strchr(buf + 2, ':');
2442146a1439SMasami Hiramatsu 	if (!p) {
2443146a1439SMasami Hiramatsu 		pr_debug("Internal error: %s should have ':' but not.\n",
2444146a1439SMasami Hiramatsu 			 ent->s);
2445146a1439SMasami Hiramatsu 		ret = -ENOTSUP;
2446146a1439SMasami Hiramatsu 		goto error;
2447146a1439SMasami Hiramatsu 	}
2448bbbb521bSMasami Hiramatsu 	*p = '/';
2449bbbb521bSMasami Hiramatsu 
24504235b045SMasami Hiramatsu 	pr_debug("Writing event: %s\n", buf);
24514235b045SMasami Hiramatsu 	ret = write(fd, buf, strlen(buf));
245244a56040SMasami Hiramatsu 	if (ret < 0) {
245344a56040SMasami Hiramatsu 		ret = -errno;
2454146a1439SMasami Hiramatsu 		goto error;
245544a56040SMasami Hiramatsu 	}
2456146a1439SMasami Hiramatsu 
24575e17b28fSMasami Hiramatsu 	pr_info("Removed event: %s\n", ent->s);
2458146a1439SMasami Hiramatsu 	return 0;
2459146a1439SMasami Hiramatsu error:
24605f03cba4SMasami Hiramatsu 	pr_warning("Failed to delete event: %s\n",
24615f03cba4SMasami Hiramatsu 		   strerror_r(-ret, buf, sizeof(buf)));
2462146a1439SMasami Hiramatsu 	return ret;
2463bbbb521bSMasami Hiramatsu }
2464bbbb521bSMasami Hiramatsu 
2465225466f1SSrikar Dronamraju static int del_trace_probe_event(int fd, const char *buf,
2466225466f1SSrikar Dronamraju 						  struct strlist *namelist)
2467fa28244dSMasami Hiramatsu {
2468bbbb521bSMasami Hiramatsu 	struct str_node *ent, *n;
2469225466f1SSrikar Dronamraju 	int ret = -1;
2470fa28244dSMasami Hiramatsu 
2471bbbb521bSMasami Hiramatsu 	if (strpbrk(buf, "*?")) { /* Glob-exp */
2472bbbb521bSMasami Hiramatsu 		strlist__for_each_safe(ent, n, namelist)
2473bbbb521bSMasami Hiramatsu 			if (strglobmatch(ent->s, buf)) {
24740e60836bSSrikar Dronamraju 				ret = __del_trace_probe_event(fd, ent);
2475146a1439SMasami Hiramatsu 				if (ret < 0)
2476146a1439SMasami Hiramatsu 					break;
24773e340590SMasami Hiramatsu 				strlist__remove(namelist, ent);
2478fa28244dSMasami Hiramatsu 			}
2479bbbb521bSMasami Hiramatsu 	} else {
2480bbbb521bSMasami Hiramatsu 		ent = strlist__find(namelist, buf);
2481bbbb521bSMasami Hiramatsu 		if (ent) {
24820e60836bSSrikar Dronamraju 			ret = __del_trace_probe_event(fd, ent);
2483146a1439SMasami Hiramatsu 			if (ret >= 0)
2484bbbb521bSMasami Hiramatsu 				strlist__remove(namelist, ent);
2485bbbb521bSMasami Hiramatsu 		}
2486bbbb521bSMasami Hiramatsu 	}
2487146a1439SMasami Hiramatsu 
2488146a1439SMasami Hiramatsu 	return ret;
2489bbbb521bSMasami Hiramatsu }
2490fa28244dSMasami Hiramatsu 
2491146a1439SMasami Hiramatsu int del_perf_probe_events(struct strlist *dellist)
2492fa28244dSMasami Hiramatsu {
2493225466f1SSrikar Dronamraju 	int ret = -1, ufd = -1, kfd = -1;
2494225466f1SSrikar Dronamraju 	char buf[128];
2495fa28244dSMasami Hiramatsu 	const char *group, *event;
2496fa28244dSMasami Hiramatsu 	char *p, *str;
2497fa28244dSMasami Hiramatsu 	struct str_node *ent;
2498225466f1SSrikar Dronamraju 	struct strlist *namelist = NULL, *unamelist = NULL;
2499146a1439SMasami Hiramatsu 
2500fa28244dSMasami Hiramatsu 	/* Get current event names */
2501225466f1SSrikar Dronamraju 	kfd = open_kprobe_events(true);
2502467ec085SMasami Hiramatsu 	if (kfd >= 0)
2503225466f1SSrikar Dronamraju 		namelist = get_probe_trace_event_names(kfd, true);
2504225466f1SSrikar Dronamraju 
2505467ec085SMasami Hiramatsu 	ufd = open_uprobe_events(true);
2506467ec085SMasami Hiramatsu 	if (ufd >= 0)
2507225466f1SSrikar Dronamraju 		unamelist = get_probe_trace_event_names(ufd, true);
2508225466f1SSrikar Dronamraju 
2509467ec085SMasami Hiramatsu 	if (kfd < 0 && ufd < 0) {
2510467ec085SMasami Hiramatsu 		print_both_open_warning(kfd, ufd);
2511467ec085SMasami Hiramatsu 		goto error;
2512467ec085SMasami Hiramatsu 	}
2513467ec085SMasami Hiramatsu 
2514225466f1SSrikar Dronamraju 	if (namelist == NULL && unamelist == NULL)
2515225466f1SSrikar Dronamraju 		goto error;
2516fa28244dSMasami Hiramatsu 
2517adf365f4SMasami Hiramatsu 	strlist__for_each(ent, dellist) {
251802b95dadSMasami Hiramatsu 		str = strdup(ent->s);
251902b95dadSMasami Hiramatsu 		if (str == NULL) {
252002b95dadSMasami Hiramatsu 			ret = -ENOMEM;
2521225466f1SSrikar Dronamraju 			goto error;
252202b95dadSMasami Hiramatsu 		}
2523bbbb521bSMasami Hiramatsu 		pr_debug("Parsing: %s\n", str);
2524fa28244dSMasami Hiramatsu 		p = strchr(str, ':');
2525fa28244dSMasami Hiramatsu 		if (p) {
2526fa28244dSMasami Hiramatsu 			group = str;
2527fa28244dSMasami Hiramatsu 			*p = '\0';
2528fa28244dSMasami Hiramatsu 			event = p + 1;
2529fa28244dSMasami Hiramatsu 		} else {
2530bbbb521bSMasami Hiramatsu 			group = "*";
2531fa28244dSMasami Hiramatsu 			event = str;
2532fa28244dSMasami Hiramatsu 		}
2533225466f1SSrikar Dronamraju 
2534225466f1SSrikar Dronamraju 		ret = e_snprintf(buf, 128, "%s:%s", group, event);
2535225466f1SSrikar Dronamraju 		if (ret < 0) {
2536225466f1SSrikar Dronamraju 			pr_err("Failed to copy event.");
2537fa28244dSMasami Hiramatsu 			free(str);
2538225466f1SSrikar Dronamraju 			goto error;
2539fa28244dSMasami Hiramatsu 		}
2540225466f1SSrikar Dronamraju 
2541225466f1SSrikar Dronamraju 		pr_debug("Group: %s, Event: %s\n", group, event);
2542225466f1SSrikar Dronamraju 
2543225466f1SSrikar Dronamraju 		if (namelist)
2544225466f1SSrikar Dronamraju 			ret = del_trace_probe_event(kfd, buf, namelist);
2545225466f1SSrikar Dronamraju 
2546225466f1SSrikar Dronamraju 		if (unamelist && ret != 0)
2547225466f1SSrikar Dronamraju 			ret = del_trace_probe_event(ufd, buf, unamelist);
2548225466f1SSrikar Dronamraju 
2549225466f1SSrikar Dronamraju 		if (ret != 0)
2550225466f1SSrikar Dronamraju 			pr_info("Info: Event \"%s\" does not exist.\n", buf);
2551225466f1SSrikar Dronamraju 
2552225466f1SSrikar Dronamraju 		free(str);
2553225466f1SSrikar Dronamraju 	}
2554225466f1SSrikar Dronamraju 
2555225466f1SSrikar Dronamraju error:
2556225466f1SSrikar Dronamraju 	if (kfd >= 0) {
2557fa28244dSMasami Hiramatsu 		strlist__delete(namelist);
2558225466f1SSrikar Dronamraju 		close(kfd);
2559225466f1SSrikar Dronamraju 	}
2560225466f1SSrikar Dronamraju 
2561225466f1SSrikar Dronamraju 	if (ufd >= 0) {
2562225466f1SSrikar Dronamraju 		strlist__delete(unamelist);
2563225466f1SSrikar Dronamraju 		close(ufd);
2564225466f1SSrikar Dronamraju 	}
2565146a1439SMasami Hiramatsu 
2566146a1439SMasami Hiramatsu 	return ret;
2567fa28244dSMasami Hiramatsu }
2568225466f1SSrikar Dronamraju 
25693c42258cSMasami Hiramatsu /* TODO: don't use a global variable for filter ... */
25703c42258cSMasami Hiramatsu static struct strfilter *available_func_filter;
2571fa28244dSMasami Hiramatsu 
2572e80711caSMasami Hiramatsu /*
25733c42258cSMasami Hiramatsu  * If a symbol corresponds to a function with global binding and
25743c42258cSMasami Hiramatsu  * matches filter return 0. For all others return 1.
2575e80711caSMasami Hiramatsu  */
25761d037ca1SIrina Tirdea static int filter_available_functions(struct map *map __maybe_unused,
2577e80711caSMasami Hiramatsu 				      struct symbol *sym)
2578e80711caSMasami Hiramatsu {
2579eb948e50SMasami Hiramatsu 	if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) &&
25803c42258cSMasami Hiramatsu 	    strfilter__compare(available_func_filter, sym->name))
2581e80711caSMasami Hiramatsu 		return 0;
25823c42258cSMasami Hiramatsu 	return 1;
2583e80711caSMasami Hiramatsu }
2584e80711caSMasami Hiramatsu 
25852df58634SMasami Hiramatsu int show_available_funcs(const char *target, struct strfilter *_filter,
25862df58634SMasami Hiramatsu 					bool user)
2587e80711caSMasami Hiramatsu {
25882df58634SMasami Hiramatsu 	struct map *map;
25892df58634SMasami Hiramatsu 	int ret;
25902df58634SMasami Hiramatsu 
25912df58634SMasami Hiramatsu 	ret = init_symbol_maps(user);
25922df58634SMasami Hiramatsu 	if (ret < 0)
25932df58634SMasami Hiramatsu 		return ret;
25942df58634SMasami Hiramatsu 
25952df58634SMasami Hiramatsu 	/* Get a symbol map */
25962df58634SMasami Hiramatsu 	if (user)
25972df58634SMasami Hiramatsu 		map = dso__new_map(target);
25982df58634SMasami Hiramatsu 	else
25992df58634SMasami Hiramatsu 		map = kernel_get_module_map(target);
26002df58634SMasami Hiramatsu 	if (!map) {
26012df58634SMasami Hiramatsu 		pr_err("Failed to get a map for %s\n", (target) ? : "kernel");
2602e80711caSMasami Hiramatsu 		return -EINVAL;
2603e80711caSMasami Hiramatsu 	}
26042df58634SMasami Hiramatsu 
26052df58634SMasami Hiramatsu 	/* Load symbols with given filter */
26062df58634SMasami Hiramatsu 	available_func_filter = _filter;
26072df58634SMasami Hiramatsu 	if (map__load(map, filter_available_functions)) {
26082df58634SMasami Hiramatsu 		pr_err("Failed to load symbols in %s\n", (target) ? : "kernel");
26092df58634SMasami Hiramatsu 		goto end;
26102df58634SMasami Hiramatsu 	}
2611e80711caSMasami Hiramatsu 	if (!dso__sorted_by_name(map->dso, map->type))
2612e80711caSMasami Hiramatsu 		dso__sort_by_name(map->dso, map->type);
2613e80711caSMasami Hiramatsu 
26142df58634SMasami Hiramatsu 	/* Show all (filtered) symbols */
26152df58634SMasami Hiramatsu 	setup_pager();
2616e80711caSMasami Hiramatsu 	dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
26172df58634SMasami Hiramatsu end:
26182df58634SMasami Hiramatsu 	if (user) {
2619225466f1SSrikar Dronamraju 		dso__delete(map->dso);
2620225466f1SSrikar Dronamraju 		map__delete(map);
2621225466f1SSrikar Dronamraju 	}
26222df58634SMasami Hiramatsu 	exit_symbol_maps();
2623225466f1SSrikar Dronamraju 
26242df58634SMasami Hiramatsu 	return ret;
2625225466f1SSrikar Dronamraju }
2626225466f1SSrikar Dronamraju 
2627