xref: /linux/tools/perf/util/probe-event.c (revision 36ec807b627b4c0a0a382f0ae48eac7187d14b2b)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
250656eecSMasami Hiramatsu /*
30e60836bSSrikar Dronamraju  * probe-event.c : perf-probe definition to probe_events format converter
450656eecSMasami Hiramatsu  *
550656eecSMasami Hiramatsu  * Written by Masami Hiramatsu <mhiramat@redhat.com>
650656eecSMasami Hiramatsu  */
750656eecSMasami Hiramatsu 
8fd20e811SArnaldo Carvalho de Melo #include <inttypes.h>
950656eecSMasami Hiramatsu #include <sys/utsname.h>
1050656eecSMasami Hiramatsu #include <sys/types.h>
1150656eecSMasami Hiramatsu #include <sys/stat.h>
1250656eecSMasami Hiramatsu #include <fcntl.h>
1350656eecSMasami Hiramatsu #include <errno.h>
1458103715SArnaldo Carvalho de Melo #include <libgen.h>
1550656eecSMasami Hiramatsu #include <stdio.h>
1650656eecSMasami Hiramatsu #include <unistd.h>
1750656eecSMasami Hiramatsu #include <stdlib.h>
1850656eecSMasami Hiramatsu #include <string.h>
194de189feSMasami Hiramatsu #include <stdarg.h>
204de189feSMasami Hiramatsu #include <limits.h>
21e80711caSMasami Hiramatsu #include <elf.h>
2250656eecSMasami Hiramatsu 
234a3cec84SArnaldo Carvalho de Melo #include "build-id.h"
2450656eecSMasami Hiramatsu #include "event.h"
2540f3b2d2SArnaldo Carvalho de Melo #include "namespaces.h"
264de189feSMasami Hiramatsu #include "strlist.h"
278ec20b17SArnaldo Carvalho de Melo #include "strfilter.h"
2850656eecSMasami Hiramatsu #include "debug.h"
294a3cec84SArnaldo Carvalho de Melo #include "dso.h"
30631c9defSMasami Hiramatsu #include "color.h"
311101f69aSArnaldo Carvalho de Melo #include "map.h"
32c54d241bSArnaldo Carvalho de Melo #include "maps.h"
33e54dea69SIan Rogers #include "mutex.h"
34e0faa8d3SMasami Hiramatsu #include "symbol.h"
354605eab3SJiri Olsa #include <api/fs/fs.h>
361d037ca1SIrina Tirdea #include "trace-event.h"	/* For __maybe_unused */
3750656eecSMasami Hiramatsu #include "probe-event.h"
384235b045SMasami Hiramatsu #include "probe-finder.h"
3992f6c72eSMasami Hiramatsu #include "probe-file.h"
40225466f1SSrikar Dronamraju #include "session.h"
41a067558eSArnaldo Carvalho de Melo #include "string2.h"
42fa0d9846SArnaldo Carvalho de Melo #include "strbuf.h"
4350656eecSMasami Hiramatsu 
44fa0d9846SArnaldo Carvalho de Melo #include <subcmd/pager.h>
453052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h>
467f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
473d689ed6SArnaldo Carvalho de Melo 
487cd5738dSMasami Hiramatsu #ifdef HAVE_DEBUGINFOD_SUPPORT
497cd5738dSMasami Hiramatsu #include <elfutils/debuginfod.h>
507cd5738dSMasami Hiramatsu #endif
517cd5738dSMasami Hiramatsu 
5250656eecSMasami Hiramatsu #define PERFPROBE_GROUP "probe"
5350656eecSMasami Hiramatsu 
54f4d7da49SMasami Hiramatsu bool probe_event_dry_run;	/* Dry run flag */
55cb402730SMasami Hiramatsu struct probe_conf probe_conf = { .magic_num = DEFAULT_PROBE_MAGIC_NUM };
56f4d7da49SMasami Hiramatsu 
57aeb50d3fSArnaldo Carvalho de Melo static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
58aeb50d3fSArnaldo Carvalho de Melo 
59146a1439SMasami Hiramatsu #define semantic_error(msg ...) pr_err("Semantic error :" msg)
6050656eecSMasami Hiramatsu 
6192f6c72eSMasami Hiramatsu 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 
73ee45b6c2SMasami Hiramatsu static struct machine *host_machine;
74e0faa8d3SMasami Hiramatsu 
75469b9b88SMasami Hiramatsu /* Initialize symbol maps and path of vmlinux/modules */
769bae1e8cSNamhyung Kim int init_probe_symbol_maps(bool user_only)
77e0faa8d3SMasami Hiramatsu {
78146a1439SMasami Hiramatsu 	int ret;
79146a1439SMasami Hiramatsu 
80680d926aSNamhyung Kim 	symbol_conf.allow_aliases = true;
810a7e6d1bSNamhyung Kim 	ret = symbol__init(NULL);
82146a1439SMasami Hiramatsu 	if (ret < 0) {
83146a1439SMasami Hiramatsu 		pr_debug("Failed to init symbol map.\n");
84146a1439SMasami Hiramatsu 		goto out;
85146a1439SMasami Hiramatsu 	}
86e0faa8d3SMasami Hiramatsu 
87ee45b6c2SMasami Hiramatsu 	if (host_machine || user_only)	/* already initialized */
88ee45b6c2SMasami Hiramatsu 		return 0;
89d28c6223SArnaldo Carvalho de Melo 
90ee45b6c2SMasami Hiramatsu 	if (symbol_conf.vmlinux_name)
91ee45b6c2SMasami Hiramatsu 		pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
92ee45b6c2SMasami Hiramatsu 
93ee45b6c2SMasami Hiramatsu 	host_machine = machine__new_host();
94ee45b6c2SMasami Hiramatsu 	if (!host_machine) {
95ee45b6c2SMasami Hiramatsu 		pr_debug("machine__new_host() failed.\n");
96ee45b6c2SMasami Hiramatsu 		symbol__exit();
97ee45b6c2SMasami Hiramatsu 		ret = -1;
98469b9b88SMasami Hiramatsu 	}
99146a1439SMasami Hiramatsu out:
100146a1439SMasami Hiramatsu 	if (ret < 0)
101146a1439SMasami Hiramatsu 		pr_warning("Failed to init vmlinux path.\n");
102146a1439SMasami Hiramatsu 	return ret;
103e0faa8d3SMasami Hiramatsu }
104e0faa8d3SMasami Hiramatsu 
1059bae1e8cSNamhyung Kim void exit_probe_symbol_maps(void)
106ee45b6c2SMasami Hiramatsu {
107ee45b6c2SMasami Hiramatsu 	machine__delete(host_machine);
108ee45b6c2SMasami Hiramatsu 	host_machine = NULL;
109ee45b6c2SMasami Hiramatsu 	symbol__exit();
110ee45b6c2SMasami Hiramatsu }
111ee45b6c2SMasami Hiramatsu 
11280526491SMasami Hiramatsu static struct ref_reloc_sym *kernel_get_ref_reloc_sym(struct map **pmap)
1138f33f7deSMasami Hiramatsu {
1148f33f7deSMasami Hiramatsu 	struct kmap *kmap;
115a5e813c6SArnaldo Carvalho de Melo 	struct map *map = machine__kernel_map(host_machine);
1168f33f7deSMasami Hiramatsu 
117be39db9fSArnaldo Carvalho de Melo 	if (map__load(map) < 0)
1188f33f7deSMasami Hiramatsu 		return NULL;
1198f33f7deSMasami Hiramatsu 
12077e65977SArnaldo Carvalho de Melo 	kmap = map__kmap(map);
121ba92732eSWang Nan 	if (!kmap)
122ba92732eSWang Nan 		return NULL;
12380526491SMasami Hiramatsu 
12480526491SMasami Hiramatsu 	if (pmap)
12580526491SMasami Hiramatsu 		*pmap = map;
12680526491SMasami Hiramatsu 
1278f33f7deSMasami Hiramatsu 	return kmap->ref_reloc_sym;
1288f33f7deSMasami Hiramatsu }
1298f33f7deSMasami Hiramatsu 
1309b239a12SMasami Hiramatsu static int kernel_get_symbol_address_by_name(const char *name, u64 *addr,
1319b239a12SMasami Hiramatsu 					     bool reloc, bool reladdr)
1328f33f7deSMasami Hiramatsu {
1338f33f7deSMasami Hiramatsu 	struct ref_reloc_sym *reloc_sym;
1348f33f7deSMasami Hiramatsu 	struct symbol *sym;
1358f33f7deSMasami Hiramatsu 	struct map *map;
1368f33f7deSMasami Hiramatsu 
1378f33f7deSMasami Hiramatsu 	/* ref_reloc_sym is just a label. Need a special fix*/
138ac7a75d1SMasami Hiramatsu 	reloc_sym = kernel_get_ref_reloc_sym(&map);
1398f33f7deSMasami Hiramatsu 	if (reloc_sym && strcmp(name, reloc_sym->name) == 0)
1402a6e5e8aSIan Rogers 		*addr = (!map__reloc(map) || reloc) ? reloc_sym->addr :
141ac7a75d1SMasami Hiramatsu 			reloc_sym->unrelocated_addr;
1428f33f7deSMasami Hiramatsu 	else {
143107cad95SArnaldo Carvalho de Melo 		sym = machine__find_kernel_symbol_by_name(host_machine, name, &map);
1449b239a12SMasami Hiramatsu 		if (!sym)
1459b239a12SMasami Hiramatsu 			return -ENOENT;
14678a1f7cdSIan Rogers 		*addr = map__unmap_ip(map, sym->start) -
1472a6e5e8aSIan Rogers 			((reloc) ? 0 : map__reloc(map)) -
148e5116f46SIan Rogers 			((reladdr) ? map__start(map) : 0);
1498f33f7deSMasami Hiramatsu 	}
1508f33f7deSMasami Hiramatsu 	return 0;
1518f33f7deSMasami Hiramatsu }
1528f33f7deSMasami Hiramatsu 
153300b53d5SIan Rogers struct kernel_get_module_map_cb_args {
154300b53d5SIan Rogers 	const char *module;
155300b53d5SIan Rogers 	struct map *result;
156300b53d5SIan Rogers };
157300b53d5SIan Rogers 
158300b53d5SIan Rogers static int kernel_get_module_map_cb(struct map *map, void *data)
159300b53d5SIan Rogers {
160300b53d5SIan Rogers 	struct kernel_get_module_map_cb_args *args = data;
161300b53d5SIan Rogers 	struct dso *dso = map__dso(map);
162*ee756ef7SIan Rogers 	const char *short_name = dso__short_name(dso);
163*ee756ef7SIan Rogers 	u16 short_name_len =  dso__short_name_len(dso);
164300b53d5SIan Rogers 
165300b53d5SIan Rogers 	if (strncmp(short_name + 1, args->module, short_name_len - 2) == 0 &&
166300b53d5SIan Rogers 	    args->module[short_name_len - 2] == '\0') {
167300b53d5SIan Rogers 		args->result = map__get(map);
168300b53d5SIan Rogers 		return 1;
169300b53d5SIan Rogers 	}
170300b53d5SIan Rogers 	return 0;
171300b53d5SIan Rogers }
172300b53d5SIan Rogers 
173e80711caSMasami Hiramatsu static struct map *kernel_get_module_map(const char *module)
174e80711caSMasami Hiramatsu {
175300b53d5SIan Rogers 	struct kernel_get_module_map_cb_args args = {
176300b53d5SIan Rogers 		.module = module,
177300b53d5SIan Rogers 		.result = NULL,
178300b53d5SIan Rogers 	};
179e80711caSMasami Hiramatsu 
18014a8fd7cSMasami Hiramatsu 	/* A file path -- this is an offline module */
18114a8fd7cSMasami Hiramatsu 	if (module && strchr(module, '/'))
182eebc509bSMasami Hiramatsu 		return dso__new_map(module);
18314a8fd7cSMasami Hiramatsu 
184eaeffeb9SAdrian Hunter 	if (!module) {
185ff583dc4SIan Rogers 		struct map *map = machine__kernel_map(host_machine);
186ff583dc4SIan Rogers 
187ff583dc4SIan Rogers 		return map__get(map);
188eaeffeb9SAdrian Hunter 	}
189e80711caSMasami Hiramatsu 
190300b53d5SIan Rogers 	maps__for_each_map(machine__kernel_maps(host_machine), kernel_get_module_map_cb, &args);
191ff583dc4SIan Rogers 
192300b53d5SIan Rogers 	return args.result;
193e80711caSMasami Hiramatsu }
194e80711caSMasami Hiramatsu 
195544abd44SKrister Johansen struct map *get_target_map(const char *target, struct nsinfo *nsi, bool user)
1969b118acaSMasami Hiramatsu {
1979b118acaSMasami Hiramatsu 	/* Init maps of given executable or kernel */
198544abd44SKrister Johansen 	if (user) {
199544abd44SKrister Johansen 		struct map *map;
20063df0e4bSIan Rogers 		struct dso *dso;
201544abd44SKrister Johansen 
202544abd44SKrister Johansen 		map = dso__new_map(target);
20363df0e4bSIan Rogers 		dso = map ? map__dso(map) : NULL;
20463df0e4bSIan Rogers 		if (dso) {
205*ee756ef7SIan Rogers 			mutex_lock(dso__lock(dso));
206*ee756ef7SIan Rogers 			dso__set_nsinfo(dso, nsinfo__get(nsi));
207*ee756ef7SIan Rogers 			mutex_unlock(dso__lock(dso));
208dedeb4beSRiccardo Mancini 		}
209544abd44SKrister Johansen 		return map;
210544abd44SKrister Johansen 	} else {
2119b118acaSMasami Hiramatsu 		return kernel_get_module_map(target);
2129b118acaSMasami Hiramatsu 	}
213544abd44SKrister Johansen }
2149b118acaSMasami Hiramatsu 
215fb7345bbSMasami Hiramatsu static int convert_exec_to_group(const char *exec, char **result)
216fb7345bbSMasami Hiramatsu {
217fb7345bbSMasami Hiramatsu 	char *ptr1, *ptr2, *exec_copy;
218fb7345bbSMasami Hiramatsu 	char buf[64];
219fb7345bbSMasami Hiramatsu 	int ret;
220fb7345bbSMasami Hiramatsu 
221fb7345bbSMasami Hiramatsu 	exec_copy = strdup(exec);
222fb7345bbSMasami Hiramatsu 	if (!exec_copy)
223fb7345bbSMasami Hiramatsu 		return -ENOMEM;
224fb7345bbSMasami Hiramatsu 
225fb7345bbSMasami Hiramatsu 	ptr1 = basename(exec_copy);
226fb7345bbSMasami Hiramatsu 	if (!ptr1) {
227fb7345bbSMasami Hiramatsu 		ret = -EINVAL;
228fb7345bbSMasami Hiramatsu 		goto out;
229fb7345bbSMasami Hiramatsu 	}
230fb7345bbSMasami Hiramatsu 
231ead1a574SColin Ian King 	for (ptr2 = ptr1; *ptr2 != '\0'; ptr2++) {
23235726d3aSMasami Hiramatsu 		if (!isalnum(*ptr2) && *ptr2 != '_') {
233fb7345bbSMasami Hiramatsu 			*ptr2 = '\0';
23435726d3aSMasami Hiramatsu 			break;
23535726d3aSMasami Hiramatsu 		}
23635726d3aSMasami Hiramatsu 	}
23735726d3aSMasami Hiramatsu 
238a529bec0SDima Kogan 	ret = e_snprintf(buf, sizeof(buf), "%s_%s", PERFPROBE_GROUP, ptr1);
239fb7345bbSMasami Hiramatsu 	if (ret < 0)
240fb7345bbSMasami Hiramatsu 		goto out;
241fb7345bbSMasami Hiramatsu 
242fb7345bbSMasami Hiramatsu 	*result = strdup(buf);
243fb7345bbSMasami Hiramatsu 	ret = *result ? 0 : -ENOMEM;
244fb7345bbSMasami Hiramatsu 
245fb7345bbSMasami Hiramatsu out:
246fb7345bbSMasami Hiramatsu 	free(exec_copy);
247fb7345bbSMasami Hiramatsu 	return ret;
248fb7345bbSMasami Hiramatsu }
249fb7345bbSMasami Hiramatsu 
2509b118acaSMasami Hiramatsu static void clear_perf_probe_point(struct perf_probe_point *pp)
2519b118acaSMasami Hiramatsu {
252d8f9da24SArnaldo Carvalho de Melo 	zfree(&pp->file);
253d8f9da24SArnaldo Carvalho de Melo 	zfree(&pp->function);
254d8f9da24SArnaldo Carvalho de Melo 	zfree(&pp->lazy_line);
2559b118acaSMasami Hiramatsu }
2569b118acaSMasami Hiramatsu 
257eb948e50SMasami Hiramatsu static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
258eb948e50SMasami Hiramatsu {
259eb948e50SMasami Hiramatsu 	int i;
260eb948e50SMasami Hiramatsu 
261eb948e50SMasami Hiramatsu 	for (i = 0; i < ntevs; i++)
262eb948e50SMasami Hiramatsu 		clear_probe_trace_event(tevs + i);
263eb948e50SMasami Hiramatsu }
264eb948e50SMasami Hiramatsu 
26522a66551SYang Jihong static bool kprobe_blacklist__listed(u64 address);
26622a66551SYang Jihong static bool kprobe_warn_out_range(const char *symbol, u64 address)
267b031220dSMasami Hiramatsu {
2682ae5d0d7SMasami Hiramatsu 	struct map *map;
2692ae5d0d7SMasami Hiramatsu 	bool ret = false;
2707c31bb8cSHe Kuang 
2712ae5d0d7SMasami Hiramatsu 	map = kernel_get_module_map(NULL);
2722ae5d0d7SMasami Hiramatsu 	if (map) {
273e5116f46SIan Rogers 		ret = address <= map__start(map) || map__end(map) < address;
2742ae5d0d7SMasami Hiramatsu 		if (ret)
275b031220dSMasami Hiramatsu 			pr_warning("%s is out of .text, skip it.\n", symbol);
2762ae5d0d7SMasami Hiramatsu 		map__put(map);
2772ae5d0d7SMasami Hiramatsu 	}
2782ae5d0d7SMasami Hiramatsu 	if (!ret && kprobe_blacklist__listed(address)) {
279b031220dSMasami Hiramatsu 		pr_warning("%s is blacklisted function, skip it.\n", symbol);
2802ae5d0d7SMasami Hiramatsu 		ret = true;
2812ae5d0d7SMasami Hiramatsu 	}
282b031220dSMasami Hiramatsu 
2832ae5d0d7SMasami Hiramatsu 	return ret;
284b031220dSMasami Hiramatsu }
285b031220dSMasami Hiramatsu 
286c61fb959SRavi Bangoria /*
287c61fb959SRavi Bangoria  * @module can be module name of module file path. In case of path,
288c61fb959SRavi Bangoria  * inspect elf and find out what is actual module name.
289c61fb959SRavi Bangoria  * Caller has to free mod_name after using it.
290c61fb959SRavi Bangoria  */
291c61fb959SRavi Bangoria static char *find_module_name(const char *module)
292c61fb959SRavi Bangoria {
293c61fb959SRavi Bangoria 	int fd;
294c61fb959SRavi Bangoria 	Elf *elf;
295c61fb959SRavi Bangoria 	GElf_Ehdr ehdr;
296c61fb959SRavi Bangoria 	GElf_Shdr shdr;
297c61fb959SRavi Bangoria 	Elf_Data *data;
298c61fb959SRavi Bangoria 	Elf_Scn *sec;
299c61fb959SRavi Bangoria 	char *mod_name = NULL;
3001f2ed153SMasami Hiramatsu 	int name_offset;
301c61fb959SRavi Bangoria 
302c61fb959SRavi Bangoria 	fd = open(module, O_RDONLY);
303c61fb959SRavi Bangoria 	if (fd < 0)
304c61fb959SRavi Bangoria 		return NULL;
305c61fb959SRavi Bangoria 
306c61fb959SRavi Bangoria 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
307c61fb959SRavi Bangoria 	if (elf == NULL)
308c61fb959SRavi Bangoria 		goto elf_err;
309c61fb959SRavi Bangoria 
310c61fb959SRavi Bangoria 	if (gelf_getehdr(elf, &ehdr) == NULL)
311c61fb959SRavi Bangoria 		goto ret_err;
312c61fb959SRavi Bangoria 
313c61fb959SRavi Bangoria 	sec = elf_section_by_name(elf, &ehdr, &shdr,
314c61fb959SRavi Bangoria 			".gnu.linkonce.this_module", NULL);
315c61fb959SRavi Bangoria 	if (!sec)
316c61fb959SRavi Bangoria 		goto ret_err;
317c61fb959SRavi Bangoria 
318c61fb959SRavi Bangoria 	data = elf_getdata(sec, NULL);
319c61fb959SRavi Bangoria 	if (!data || !data->d_buf)
320c61fb959SRavi Bangoria 		goto ret_err;
321c61fb959SRavi Bangoria 
3221f2ed153SMasami Hiramatsu 	/*
3231f2ed153SMasami Hiramatsu 	 * NOTE:
3241f2ed153SMasami Hiramatsu 	 * '.gnu.linkonce.this_module' section of kernel module elf directly
3251f2ed153SMasami Hiramatsu 	 * maps to 'struct module' from linux/module.h. This section contains
3261f2ed153SMasami Hiramatsu 	 * actual module name which will be used by kernel after loading it.
3271f2ed153SMasami Hiramatsu 	 * But, we cannot use 'struct module' here since linux/module.h is not
3281f2ed153SMasami Hiramatsu 	 * exposed to user-space. Offset of 'name' has remained same from long
3291f2ed153SMasami Hiramatsu 	 * time, so hardcoding it here.
3301f2ed153SMasami Hiramatsu 	 */
3311f2ed153SMasami Hiramatsu 	if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
3321f2ed153SMasami Hiramatsu 		name_offset = 12;
3331f2ed153SMasami Hiramatsu 	else	/* expect ELFCLASS64 by default */
3341f2ed153SMasami Hiramatsu 		name_offset = 24;
3351f2ed153SMasami Hiramatsu 
3361f2ed153SMasami Hiramatsu 	mod_name = strdup((char *)data->d_buf + name_offset);
337c61fb959SRavi Bangoria 
338c61fb959SRavi Bangoria ret_err:
339c61fb959SRavi Bangoria 	elf_end(elf);
340c61fb959SRavi Bangoria elf_err:
341c61fb959SRavi Bangoria 	close(fd);
342c61fb959SRavi Bangoria 	return mod_name;
343c61fb959SRavi Bangoria }
344c61fb959SRavi Bangoria 
34589fe808aSIngo Molnar #ifdef HAVE_DWARF_SUPPORT
34660fb7742SWang Nan 
34760fb7742SWang Nan static int kernel_get_module_dso(const char *module, struct dso **pdso)
34860fb7742SWang Nan {
34960fb7742SWang Nan 	struct dso *dso;
35060fb7742SWang Nan 	struct map *map;
35160fb7742SWang Nan 	const char *vmlinux_name;
35260fb7742SWang Nan 	int ret = 0;
35360fb7742SWang Nan 
35460fb7742SWang Nan 	if (module) {
355266fa2b2SArnaldo Carvalho de Melo 		char module_name[128];
356266fa2b2SArnaldo Carvalho de Melo 
357266fa2b2SArnaldo Carvalho de Melo 		snprintf(module_name, sizeof(module_name), "[%s]", module);
3581a97cee6SIan Rogers 		map = maps__find_by_name(machine__kernel_maps(host_machine), module_name);
359266fa2b2SArnaldo Carvalho de Melo 		if (map) {
36063df0e4bSIan Rogers 			dso = map__dso(map);
361107ef66cSIan Rogers 			map__put(map);
36260fb7742SWang Nan 			goto found;
36360fb7742SWang Nan 		}
36460fb7742SWang Nan 		pr_debug("Failed to find module %s.\n", module);
36560fb7742SWang Nan 		return -ENOENT;
36660fb7742SWang Nan 	}
36760fb7742SWang Nan 
368a5e813c6SArnaldo Carvalho de Melo 	map = machine__kernel_map(host_machine);
36963df0e4bSIan Rogers 	dso = map__dso(map);
370*ee756ef7SIan Rogers 	if (!dso__has_build_id(dso))
3717cd5738dSMasami Hiramatsu 		dso__read_running_kernel_build_id(dso, host_machine);
37260fb7742SWang Nan 
37360fb7742SWang Nan 	vmlinux_name = symbol_conf.vmlinux_name;
374*ee756ef7SIan Rogers 	*dso__load_errno(dso) = 0;
37560fb7742SWang Nan 	if (vmlinux_name)
376be39db9fSArnaldo Carvalho de Melo 		ret = dso__load_vmlinux(dso, map, vmlinux_name, false);
37760fb7742SWang Nan 	else
378be39db9fSArnaldo Carvalho de Melo 		ret = dso__load_vmlinux_path(dso, map);
37960fb7742SWang Nan found:
38060fb7742SWang Nan 	*pdso = dso;
38160fb7742SWang Nan 	return ret;
38260fb7742SWang Nan }
38360fb7742SWang Nan 
3849b118acaSMasami Hiramatsu /*
3859b118acaSMasami Hiramatsu  * Some binaries like glibc have special symbols which are on the symbol
3869b118acaSMasami Hiramatsu  * table, but not in the debuginfo. If we can find the address of the
3879b118acaSMasami Hiramatsu  * symbol from map, we can translate the address back to the probe point.
3889b118acaSMasami Hiramatsu  */
3899b118acaSMasami Hiramatsu static int find_alternative_probe_point(struct debuginfo *dinfo,
3909b118acaSMasami Hiramatsu 					struct perf_probe_point *pp,
3919b118acaSMasami Hiramatsu 					struct perf_probe_point *result,
392544abd44SKrister Johansen 					const char *target, struct nsinfo *nsi,
393544abd44SKrister Johansen 					bool uprobes)
3949b118acaSMasami Hiramatsu {
3959b118acaSMasami Hiramatsu 	struct map *map = NULL;
3969b118acaSMasami Hiramatsu 	struct symbol *sym;
3979b118acaSMasami Hiramatsu 	u64 address = 0;
3989b118acaSMasami Hiramatsu 	int ret = -ENOENT;
399259dce91SIan Rogers 	size_t idx;
4009b118acaSMasami Hiramatsu 
4019b118acaSMasami Hiramatsu 	/* This can work only for function-name based one */
4029b118acaSMasami Hiramatsu 	if (!pp->function || pp->file)
4039b118acaSMasami Hiramatsu 		return -ENOTSUP;
4049b118acaSMasami Hiramatsu 
405544abd44SKrister Johansen 	map = get_target_map(target, nsi, uprobes);
4069b118acaSMasami Hiramatsu 	if (!map)
4079b118acaSMasami Hiramatsu 		return -EINVAL;
4089b118acaSMasami Hiramatsu 
4099b118acaSMasami Hiramatsu 	/* Find the address of given function */
410259dce91SIan Rogers 	map__for_each_symbol_by_name(map, pp->function, sym, idx) {
4113de2bf9dSMasami Hiramatsu 		if (uprobes) {
4129b118acaSMasami Hiramatsu 			address = sym->start;
4133de2bf9dSMasami Hiramatsu 			if (sym->type == STT_GNU_IFUNC)
4143de2bf9dSMasami Hiramatsu 				pr_warning("Warning: The probe function (%s) is a GNU indirect function.\n"
4153de2bf9dSMasami Hiramatsu 					   "Consider identifying the final function used at run time and set the probe directly on that.\n",
4163de2bf9dSMasami Hiramatsu 					   pp->function);
4173de2bf9dSMasami Hiramatsu 		} else
4182a6e5e8aSIan Rogers 			address = map__unmap_ip(map, sym->start) - map__reloc(map);
4199b118acaSMasami Hiramatsu 		break;
4209b118acaSMasami Hiramatsu 	}
4219b118acaSMasami Hiramatsu 	if (!address) {
4229b118acaSMasami Hiramatsu 		ret = -ENOENT;
4239b118acaSMasami Hiramatsu 		goto out;
4249b118acaSMasami Hiramatsu 	}
425f6c15621SWang Nan 	pr_debug("Symbol %s address found : %" PRIx64 "\n",
426f6c15621SWang Nan 			pp->function, address);
4279b118acaSMasami Hiramatsu 
42822a66551SYang Jihong 	ret = debuginfo__find_probe_point(dinfo, address, result);
4299b118acaSMasami Hiramatsu 	if (ret <= 0)
4309b118acaSMasami Hiramatsu 		ret = (!ret) ? -ENOENT : ret;
4319b118acaSMasami Hiramatsu 	else {
4329b118acaSMasami Hiramatsu 		result->offset += pp->offset;
4339b118acaSMasami Hiramatsu 		result->line += pp->line;
4349d7b45c5SHe Kuang 		result->retprobe = pp->retprobe;
4359b118acaSMasami Hiramatsu 		ret = 0;
4369b118acaSMasami Hiramatsu 	}
4379b118acaSMasami Hiramatsu 
4389b118acaSMasami Hiramatsu out:
439eebc509bSMasami Hiramatsu 	map__put(map);
4409b118acaSMasami Hiramatsu 	return ret;
4419b118acaSMasami Hiramatsu 
4429b118acaSMasami Hiramatsu }
4439b118acaSMasami Hiramatsu 
4449b118acaSMasami Hiramatsu static int get_alternative_probe_event(struct debuginfo *dinfo,
4459b118acaSMasami Hiramatsu 				       struct perf_probe_event *pev,
44644225521SMasami Hiramatsu 				       struct perf_probe_point *tmp)
4479b118acaSMasami Hiramatsu {
4489b118acaSMasami Hiramatsu 	int ret;
4499b118acaSMasami Hiramatsu 
4509b118acaSMasami Hiramatsu 	memcpy(tmp, &pev->point, sizeof(*tmp));
4519b118acaSMasami Hiramatsu 	memset(&pev->point, 0, sizeof(pev->point));
452544abd44SKrister Johansen 	ret = find_alternative_probe_point(dinfo, tmp, &pev->point, pev->target,
453544abd44SKrister Johansen 					   pev->nsi, pev->uprobes);
4549b118acaSMasami Hiramatsu 	if (ret < 0)
4559b118acaSMasami Hiramatsu 		memcpy(&pev->point, tmp, sizeof(*tmp));
4569b118acaSMasami Hiramatsu 
4579b118acaSMasami Hiramatsu 	return ret;
4589b118acaSMasami Hiramatsu }
459a15ad2f5SMasami Hiramatsu 
460811dd2aeSMasami Hiramatsu static int get_alternative_line_range(struct debuginfo *dinfo,
461811dd2aeSMasami Hiramatsu 				      struct line_range *lr,
462811dd2aeSMasami Hiramatsu 				      const char *target, bool user)
463811dd2aeSMasami Hiramatsu {
4646d4a4896SDavid Ahern 	struct perf_probe_point pp = { .function = lr->function,
4656d4a4896SDavid Ahern 				       .file = lr->file,
4666d4a4896SDavid Ahern 				       .line = lr->start };
4676d4a4896SDavid Ahern 	struct perf_probe_point result;
468811dd2aeSMasami Hiramatsu 	int ret, len = 0;
469811dd2aeSMasami Hiramatsu 
4706d4a4896SDavid Ahern 	memset(&result, 0, sizeof(result));
4716d4a4896SDavid Ahern 
472811dd2aeSMasami Hiramatsu 	if (lr->end != INT_MAX)
473811dd2aeSMasami Hiramatsu 		len = lr->end - lr->start;
474811dd2aeSMasami Hiramatsu 	ret = find_alternative_probe_point(dinfo, &pp, &result,
475544abd44SKrister Johansen 					   target, NULL, user);
476811dd2aeSMasami Hiramatsu 	if (!ret) {
477811dd2aeSMasami Hiramatsu 		lr->function = result.function;
478811dd2aeSMasami Hiramatsu 		lr->file = result.file;
479811dd2aeSMasami Hiramatsu 		lr->start = result.line;
480811dd2aeSMasami Hiramatsu 		if (lr->end != INT_MAX)
481811dd2aeSMasami Hiramatsu 			lr->end = lr->start + len;
482811dd2aeSMasami Hiramatsu 		clear_perf_probe_point(&pp);
483811dd2aeSMasami Hiramatsu 	}
484811dd2aeSMasami Hiramatsu 	return ret;
485811dd2aeSMasami Hiramatsu }
486811dd2aeSMasami Hiramatsu 
4877cd5738dSMasami Hiramatsu #ifdef HAVE_DEBUGINFOD_SUPPORT
4887cd5738dSMasami Hiramatsu static struct debuginfo *open_from_debuginfod(struct dso *dso, struct nsinfo *nsi,
4897cd5738dSMasami Hiramatsu 					      bool silent)
4907cd5738dSMasami Hiramatsu {
4917cd5738dSMasami Hiramatsu 	debuginfod_client *c = debuginfod_begin();
4927cd5738dSMasami Hiramatsu 	char sbuild_id[SBUILD_ID_SIZE + 1];
4937cd5738dSMasami Hiramatsu 	struct debuginfo *ret = NULL;
4947cd5738dSMasami Hiramatsu 	struct nscookie nsc;
4957cd5738dSMasami Hiramatsu 	char *path;
4967cd5738dSMasami Hiramatsu 	int fd;
4977cd5738dSMasami Hiramatsu 
4987cd5738dSMasami Hiramatsu 	if (!c)
4997cd5738dSMasami Hiramatsu 		return NULL;
5007cd5738dSMasami Hiramatsu 
501*ee756ef7SIan Rogers 	build_id__sprintf(dso__bid(dso), sbuild_id);
5027cd5738dSMasami Hiramatsu 	fd = debuginfod_find_debuginfo(c, (const unsigned char *)sbuild_id,
5037cd5738dSMasami Hiramatsu 					0, &path);
5047cd5738dSMasami Hiramatsu 	if (fd >= 0)
5057cd5738dSMasami Hiramatsu 		close(fd);
5067cd5738dSMasami Hiramatsu 	debuginfod_end(c);
5077cd5738dSMasami Hiramatsu 	if (fd < 0) {
5087cd5738dSMasami Hiramatsu 		if (!silent)
5097cd5738dSMasami Hiramatsu 			pr_debug("Failed to find debuginfo in debuginfod.\n");
5107cd5738dSMasami Hiramatsu 		return NULL;
5117cd5738dSMasami Hiramatsu 	}
5127cd5738dSMasami Hiramatsu 	if (!silent)
5137cd5738dSMasami Hiramatsu 		pr_debug("Load debuginfo from debuginfod (%s)\n", path);
5147cd5738dSMasami Hiramatsu 
5157cd5738dSMasami Hiramatsu 	nsinfo__mountns_enter(nsi, &nsc);
5167cd5738dSMasami Hiramatsu 	ret = debuginfo__new((const char *)path);
5177cd5738dSMasami Hiramatsu 	nsinfo__mountns_exit(&nsc);
5187cd5738dSMasami Hiramatsu 	return ret;
5197cd5738dSMasami Hiramatsu }
5207cd5738dSMasami Hiramatsu #else
5217cd5738dSMasami Hiramatsu static inline
5227cd5738dSMasami Hiramatsu struct debuginfo *open_from_debuginfod(struct dso *dso __maybe_unused,
5237cd5738dSMasami Hiramatsu 				       struct nsinfo *nsi __maybe_unused,
5247cd5738dSMasami Hiramatsu 				       bool silent __maybe_unused)
5257cd5738dSMasami Hiramatsu {
5267cd5738dSMasami Hiramatsu 	return NULL;
5277cd5738dSMasami Hiramatsu }
5287cd5738dSMasami Hiramatsu #endif
5297cd5738dSMasami Hiramatsu 
530ff741783SMasami Hiramatsu /* Open new debuginfo of given module */
531544abd44SKrister Johansen static struct debuginfo *open_debuginfo(const char *module, struct nsinfo *nsi,
532544abd44SKrister Johansen 					bool silent)
533469b9b88SMasami Hiramatsu {
534a15ad2f5SMasami Hiramatsu 	const char *path = module;
535419e8738SMasami Hiramatsu 	char reason[STRERR_BUFSIZE];
536419e8738SMasami Hiramatsu 	struct debuginfo *ret = NULL;
537419e8738SMasami Hiramatsu 	struct dso *dso = NULL;
538544abd44SKrister Johansen 	struct nscookie nsc;
539419e8738SMasami Hiramatsu 	int err;
54014a8fd7cSMasami Hiramatsu 
541a15ad2f5SMasami Hiramatsu 	if (!module || !strchr(module, '/')) {
542419e8738SMasami Hiramatsu 		err = kernel_get_module_dso(module, &dso);
543419e8738SMasami Hiramatsu 		if (err < 0) {
544*ee756ef7SIan Rogers 			if (!dso || *dso__load_errno(dso) == 0) {
545c8b5f2c9SArnaldo Carvalho de Melo 				if (!str_error_r(-err, reason, STRERR_BUFSIZE))
546419e8738SMasami Hiramatsu 					strcpy(reason, "(unknown)");
547419e8738SMasami Hiramatsu 			} else
548419e8738SMasami Hiramatsu 				dso__strerror_load(dso, reason, STRERR_BUFSIZE);
5497cd5738dSMasami Hiramatsu 			if (dso)
5507cd5738dSMasami Hiramatsu 				ret = open_from_debuginfod(dso, nsi, silent);
5517cd5738dSMasami Hiramatsu 			if (ret)
5527cd5738dSMasami Hiramatsu 				return ret;
5534d6101f5SArnaldo Carvalho de Melo 			if (!silent) {
5544d6101f5SArnaldo Carvalho de Melo 				if (module)
5554d6101f5SArnaldo Carvalho de Melo 					pr_err("Module %s is not loaded, please specify its full path name.\n", module);
5564d6101f5SArnaldo Carvalho de Melo 				else
5574d6101f5SArnaldo Carvalho de Melo 					pr_err("Failed to find the path for the kernel: %s\n", reason);
5584d6101f5SArnaldo Carvalho de Melo 			}
559ff741783SMasami Hiramatsu 			return NULL;
560469b9b88SMasami Hiramatsu 		}
561*ee756ef7SIan Rogers 		path = dso__long_name(dso);
56214a8fd7cSMasami Hiramatsu 	}
563544abd44SKrister Johansen 	nsinfo__mountns_enter(nsi, &nsc);
56492561cb7SMasami Hiramatsu 	ret = debuginfo__new(path);
56592561cb7SMasami Hiramatsu 	if (!ret && !silent) {
56692561cb7SMasami Hiramatsu 		pr_warning("The %s file has no debug information.\n", path);
56792561cb7SMasami Hiramatsu 		if (!module || !strtailcmp(path, ".ko"))
56892561cb7SMasami Hiramatsu 			pr_warning("Rebuild with CONFIG_DEBUG_INFO=y, ");
56992561cb7SMasami Hiramatsu 		else
57092561cb7SMasami Hiramatsu 			pr_warning("Rebuild with -g, ");
57192561cb7SMasami Hiramatsu 		pr_warning("or install an appropriate debuginfo package.\n");
572e0faa8d3SMasami Hiramatsu 	}
573544abd44SKrister Johansen 	nsinfo__mountns_exit(&nsc);
57492561cb7SMasami Hiramatsu 	return ret;
57592561cb7SMasami Hiramatsu }
57692561cb7SMasami Hiramatsu 
5777737af01SMasami Hiramatsu /* For caching the last debuginfo */
5787737af01SMasami Hiramatsu static struct debuginfo *debuginfo_cache;
5797737af01SMasami Hiramatsu static char *debuginfo_cache_path;
5807737af01SMasami Hiramatsu 
5817737af01SMasami Hiramatsu static struct debuginfo *debuginfo_cache__open(const char *module, bool silent)
5827737af01SMasami Hiramatsu {
58320f49859SMasami Hiramatsu 	const char *path = module;
58420f49859SMasami Hiramatsu 
58520f49859SMasami Hiramatsu 	/* If the module is NULL, it should be the kernel. */
58620f49859SMasami Hiramatsu 	if (!module)
58720f49859SMasami Hiramatsu 		path = "kernel";
58820f49859SMasami Hiramatsu 
58920f49859SMasami Hiramatsu 	if (debuginfo_cache_path && !strcmp(debuginfo_cache_path, path))
5907737af01SMasami Hiramatsu 		goto out;
5917737af01SMasami Hiramatsu 
5927737af01SMasami Hiramatsu 	/* Copy module path */
5937737af01SMasami Hiramatsu 	free(debuginfo_cache_path);
59420f49859SMasami Hiramatsu 	debuginfo_cache_path = strdup(path);
5957737af01SMasami Hiramatsu 	if (!debuginfo_cache_path) {
5967737af01SMasami Hiramatsu 		debuginfo__delete(debuginfo_cache);
5977737af01SMasami Hiramatsu 		debuginfo_cache = NULL;
5987737af01SMasami Hiramatsu 		goto out;
5997737af01SMasami Hiramatsu 	}
6007737af01SMasami Hiramatsu 
601544abd44SKrister Johansen 	debuginfo_cache = open_debuginfo(module, NULL, silent);
6027737af01SMasami Hiramatsu 	if (!debuginfo_cache)
6037737af01SMasami Hiramatsu 		zfree(&debuginfo_cache_path);
6047737af01SMasami Hiramatsu out:
6057737af01SMasami Hiramatsu 	return debuginfo_cache;
6067737af01SMasami Hiramatsu }
6077737af01SMasami Hiramatsu 
6087737af01SMasami Hiramatsu static void debuginfo_cache__exit(void)
6097737af01SMasami Hiramatsu {
6107737af01SMasami Hiramatsu 	debuginfo__delete(debuginfo_cache);
6117737af01SMasami Hiramatsu 	debuginfo_cache = NULL;
6127737af01SMasami Hiramatsu 	zfree(&debuginfo_cache_path);
6137737af01SMasami Hiramatsu }
6147737af01SMasami Hiramatsu 
6154b4da7f7SMasami Hiramatsu 
61622a66551SYang Jihong static int get_text_start_address(const char *exec, u64 *address,
617544abd44SKrister Johansen 				  struct nsinfo *nsi)
61899ca4233SMasami Hiramatsu {
61999ca4233SMasami Hiramatsu 	Elf *elf;
62099ca4233SMasami Hiramatsu 	GElf_Ehdr ehdr;
62199ca4233SMasami Hiramatsu 	GElf_Shdr shdr;
62299ca4233SMasami Hiramatsu 	int fd, ret = -ENOENT;
623544abd44SKrister Johansen 	struct nscookie nsc;
62499ca4233SMasami Hiramatsu 
625544abd44SKrister Johansen 	nsinfo__mountns_enter(nsi, &nsc);
62699ca4233SMasami Hiramatsu 	fd = open(exec, O_RDONLY);
627544abd44SKrister Johansen 	nsinfo__mountns_exit(&nsc);
62899ca4233SMasami Hiramatsu 	if (fd < 0)
62999ca4233SMasami Hiramatsu 		return -errno;
63099ca4233SMasami Hiramatsu 
63199ca4233SMasami Hiramatsu 	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
632062d6c2aSMasami Hiramatsu 	if (elf == NULL) {
633062d6c2aSMasami Hiramatsu 		ret = -EINVAL;
634062d6c2aSMasami Hiramatsu 		goto out_close;
635062d6c2aSMasami Hiramatsu 	}
63699ca4233SMasami Hiramatsu 
63799ca4233SMasami Hiramatsu 	if (gelf_getehdr(elf, &ehdr) == NULL)
63899ca4233SMasami Hiramatsu 		goto out;
63999ca4233SMasami Hiramatsu 
64099ca4233SMasami Hiramatsu 	if (!elf_section_by_name(elf, &ehdr, &shdr, ".text", NULL))
64199ca4233SMasami Hiramatsu 		goto out;
64299ca4233SMasami Hiramatsu 
64399ca4233SMasami Hiramatsu 	*address = shdr.sh_addr - shdr.sh_offset;
64499ca4233SMasami Hiramatsu 	ret = 0;
64599ca4233SMasami Hiramatsu out:
64699ca4233SMasami Hiramatsu 	elf_end(elf);
647062d6c2aSMasami Hiramatsu out_close:
648062d6c2aSMasami Hiramatsu 	close(fd);
649062d6c2aSMasami Hiramatsu 
65099ca4233SMasami Hiramatsu 	return ret;
65199ca4233SMasami Hiramatsu }
65299ca4233SMasami Hiramatsu 
6535a6f6314SMasami Hiramatsu /*
6545a6f6314SMasami Hiramatsu  * Convert trace point to probe point with debuginfo
6555a6f6314SMasami Hiramatsu  */
6565a6f6314SMasami Hiramatsu static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
6575a6f6314SMasami Hiramatsu 					    struct perf_probe_point *pp,
6585a6f6314SMasami Hiramatsu 					    bool is_kprobe)
6595a6f6314SMasami Hiramatsu {
6605a6f6314SMasami Hiramatsu 	struct debuginfo *dinfo = NULL;
66122a66551SYang Jihong 	u64 stext = 0;
6625a6f6314SMasami Hiramatsu 	u64 addr = tp->address;
6635a6f6314SMasami Hiramatsu 	int ret = -ENOENT;
6645a6f6314SMasami Hiramatsu 
6655a6f6314SMasami Hiramatsu 	/* convert the address to dwarf address */
6665a6f6314SMasami Hiramatsu 	if (!is_kprobe) {
6675a6f6314SMasami Hiramatsu 		if (!addr) {
6685a6f6314SMasami Hiramatsu 			ret = -EINVAL;
6695a6f6314SMasami Hiramatsu 			goto error;
6705a6f6314SMasami Hiramatsu 		}
671544abd44SKrister Johansen 		ret = get_text_start_address(tp->module, &stext, NULL);
6725a6f6314SMasami Hiramatsu 		if (ret < 0)
6735a6f6314SMasami Hiramatsu 			goto error;
6745a6f6314SMasami Hiramatsu 		addr += stext;
675e486367fSWang Nan 	} else if (tp->symbol) {
6769b239a12SMasami Hiramatsu 		/* If the module is given, this returns relative address */
6779b239a12SMasami Hiramatsu 		ret = kernel_get_symbol_address_by_name(tp->symbol, &addr,
6789b239a12SMasami Hiramatsu 							false, !!tp->module);
6799b239a12SMasami Hiramatsu 		if (ret != 0)
6805a6f6314SMasami Hiramatsu 			goto error;
6815a6f6314SMasami Hiramatsu 		addr += tp->offset;
6825a6f6314SMasami Hiramatsu 	}
6835a6f6314SMasami Hiramatsu 
6845a6f6314SMasami Hiramatsu 	pr_debug("try to find information at %" PRIx64 " in %s\n", addr,
6855a6f6314SMasami Hiramatsu 		 tp->module ? : "kernel");
6865a6f6314SMasami Hiramatsu 
687bb963e16SNamhyung Kim 	dinfo = debuginfo_cache__open(tp->module, verbose <= 0);
6887737af01SMasami Hiramatsu 	if (dinfo)
68922a66551SYang Jihong 		ret = debuginfo__find_probe_point(dinfo, addr, pp);
6907737af01SMasami Hiramatsu 	else
6915a6f6314SMasami Hiramatsu 		ret = -ENOENT;
6925a6f6314SMasami Hiramatsu 
6935a6f6314SMasami Hiramatsu 	if (ret > 0) {
6945a6f6314SMasami Hiramatsu 		pp->retprobe = tp->retprobe;
6955a6f6314SMasami Hiramatsu 		return 0;
6965a6f6314SMasami Hiramatsu 	}
6975a6f6314SMasami Hiramatsu error:
6985a6f6314SMasami Hiramatsu 	pr_debug("Failed to find corresponding probes from debuginfo.\n");
6995a6f6314SMasami Hiramatsu 	return ret ? : -ENOENT;
7005a6f6314SMasami Hiramatsu }
7015a6f6314SMasami Hiramatsu 
7023e96dac7SMasami Hiramatsu /* Adjust symbol name and address */
7033e96dac7SMasami Hiramatsu static int post_process_probe_trace_point(struct probe_trace_point *tp,
70422a66551SYang Jihong 					   struct map *map, u64 offs)
7053e96dac7SMasami Hiramatsu {
7063e96dac7SMasami Hiramatsu 	struct symbol *sym;
7077598f8bcSBjörn Töpel 	u64 addr = tp->address - offs;
7083e96dac7SMasami Hiramatsu 
7093e96dac7SMasami Hiramatsu 	sym = map__find_symbol(map, addr);
710f338de22SMasami Hiramatsu 	if (!sym) {
711f338de22SMasami Hiramatsu 		/*
712f338de22SMasami Hiramatsu 		 * If the address is in the inittext section, map can not
713f338de22SMasami Hiramatsu 		 * find it. Ignore it if we are probing offline kernel.
714f338de22SMasami Hiramatsu 		 */
715f338de22SMasami Hiramatsu 		return (symbol_conf.ignore_vmlinux_buildid) ? 0 : -ENOENT;
716f338de22SMasami Hiramatsu 	}
7173e96dac7SMasami Hiramatsu 
7183e96dac7SMasami Hiramatsu 	if (strcmp(sym->name, tp->symbol)) {
7193e96dac7SMasami Hiramatsu 		/* If we have no realname, use symbol for it */
7203e96dac7SMasami Hiramatsu 		if (!tp->realname)
7213e96dac7SMasami Hiramatsu 			tp->realname = tp->symbol;
7223e96dac7SMasami Hiramatsu 		else
7233e96dac7SMasami Hiramatsu 			free(tp->symbol);
7243e96dac7SMasami Hiramatsu 		tp->symbol = strdup(sym->name);
7253e96dac7SMasami Hiramatsu 		if (!tp->symbol)
7263e96dac7SMasami Hiramatsu 			return -ENOMEM;
7273e96dac7SMasami Hiramatsu 	}
7283e96dac7SMasami Hiramatsu 	tp->offset = addr - sym->start;
7293e96dac7SMasami Hiramatsu 	tp->address -= offs;
7303e96dac7SMasami Hiramatsu 
7313e96dac7SMasami Hiramatsu 	return 0;
7323e96dac7SMasami Hiramatsu }
7333e96dac7SMasami Hiramatsu 
7348a937a25SMasami Hiramatsu /*
7358a937a25SMasami Hiramatsu  * Rename DWARF symbols to ELF symbols -- gcc sometimes optimizes functions
7368a937a25SMasami Hiramatsu  * and generate new symbols with suffixes such as .constprop.N or .isra.N
7378a937a25SMasami Hiramatsu  * etc. Since those symbols are not recorded in DWARF, we have to find
7388a937a25SMasami Hiramatsu  * correct generated symbols from offline ELF binary.
7398a937a25SMasami Hiramatsu  * For online kernel or uprobes we don't need this because those are
7408a937a25SMasami Hiramatsu  * rebased on _text, or already a section relative address.
7418a937a25SMasami Hiramatsu  */
7428a937a25SMasami Hiramatsu static int
7438a937a25SMasami Hiramatsu post_process_offline_probe_trace_events(struct probe_trace_event *tevs,
7448a937a25SMasami Hiramatsu 					int ntevs, const char *pathname)
7458a937a25SMasami Hiramatsu {
7468a937a25SMasami Hiramatsu 	struct map *map;
74722a66551SYang Jihong 	u64 stext = 0;
7483e96dac7SMasami Hiramatsu 	int i, ret = 0;
7498a937a25SMasami Hiramatsu 
7508a937a25SMasami Hiramatsu 	/* Prepare a map for offline binary */
7518a937a25SMasami Hiramatsu 	map = dso__new_map(pathname);
752544abd44SKrister Johansen 	if (!map || get_text_start_address(pathname, &stext, NULL) < 0) {
7538a937a25SMasami Hiramatsu 		pr_warning("Failed to get ELF symbols for %s\n", pathname);
7548a937a25SMasami Hiramatsu 		return -EINVAL;
7558a937a25SMasami Hiramatsu 	}
7568a937a25SMasami Hiramatsu 
7578a937a25SMasami Hiramatsu 	for (i = 0; i < ntevs; i++) {
7583e96dac7SMasami Hiramatsu 		ret = post_process_probe_trace_point(&tevs[i].point,
7593e96dac7SMasami Hiramatsu 						     map, stext);
7603e96dac7SMasami Hiramatsu 		if (ret < 0)
7613e96dac7SMasami Hiramatsu 			break;
7628a937a25SMasami Hiramatsu 	}
7638a937a25SMasami Hiramatsu 	map__put(map);
7648a937a25SMasami Hiramatsu 
7653e96dac7SMasami Hiramatsu 	return ret;
7668a937a25SMasami Hiramatsu }
7678a937a25SMasami Hiramatsu 
768fb7345bbSMasami Hiramatsu static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
769544abd44SKrister Johansen 					  int ntevs, const char *exec,
770544abd44SKrister Johansen 					  struct nsinfo *nsi)
771fb7345bbSMasami Hiramatsu {
772fb7345bbSMasami Hiramatsu 	int i, ret = 0;
77322a66551SYang Jihong 	u64 stext = 0;
774fb7345bbSMasami Hiramatsu 
775fb7345bbSMasami Hiramatsu 	if (!exec)
776fb7345bbSMasami Hiramatsu 		return 0;
777fb7345bbSMasami Hiramatsu 
778544abd44SKrister Johansen 	ret = get_text_start_address(exec, &stext, nsi);
779fb7345bbSMasami Hiramatsu 	if (ret < 0)
780fb7345bbSMasami Hiramatsu 		return ret;
781fb7345bbSMasami Hiramatsu 
782fb7345bbSMasami Hiramatsu 	for (i = 0; i < ntevs && ret >= 0; i++) {
783adba1634SIngo Molnar 		/* point.address is the address of point.symbol + point.offset */
784eb948e50SMasami Hiramatsu 		tevs[i].point.address -= stext;
785fb7345bbSMasami Hiramatsu 		tevs[i].point.module = strdup(exec);
786eb948e50SMasami Hiramatsu 		if (!tevs[i].point.module) {
787fb7345bbSMasami Hiramatsu 			ret = -ENOMEM;
788fb7345bbSMasami Hiramatsu 			break;
789fb7345bbSMasami Hiramatsu 		}
790fb7345bbSMasami Hiramatsu 		tevs[i].uprobes = true;
791fb7345bbSMasami Hiramatsu 	}
792fb7345bbSMasami Hiramatsu 
793fb7345bbSMasami Hiramatsu 	return ret;
794fb7345bbSMasami Hiramatsu }
795fb7345bbSMasami Hiramatsu 
796613f050dSMasami Hiramatsu static int
797613f050dSMasami Hiramatsu post_process_module_probe_trace_events(struct probe_trace_event *tevs,
798613f050dSMasami Hiramatsu 				       int ntevs, const char *module,
799613f050dSMasami Hiramatsu 				       struct debuginfo *dinfo)
800190b57fcSMasami Hiramatsu {
801613f050dSMasami Hiramatsu 	Dwarf_Addr text_offs = 0;
80214a8fd7cSMasami Hiramatsu 	int i, ret = 0;
80363a29613SRavi Bangoria 	char *mod_name = NULL;
804613f050dSMasami Hiramatsu 	struct map *map;
80514a8fd7cSMasami Hiramatsu 
80614a8fd7cSMasami Hiramatsu 	if (!module)
80714a8fd7cSMasami Hiramatsu 		return 0;
80814a8fd7cSMasami Hiramatsu 
809544abd44SKrister Johansen 	map = get_target_map(module, NULL, false);
810613f050dSMasami Hiramatsu 	if (!map || debuginfo__get_text_offset(dinfo, &text_offs, true) < 0) {
811613f050dSMasami Hiramatsu 		pr_warning("Failed to get ELF symbols for %s\n", module);
812613f050dSMasami Hiramatsu 		return -EINVAL;
813613f050dSMasami Hiramatsu 	}
81414a8fd7cSMasami Hiramatsu 
815613f050dSMasami Hiramatsu 	mod_name = find_module_name(module);
816190b57fcSMasami Hiramatsu 	for (i = 0; i < ntevs; i++) {
817613f050dSMasami Hiramatsu 		ret = post_process_probe_trace_point(&tevs[i].point,
81822a66551SYang Jihong 						map, text_offs);
819613f050dSMasami Hiramatsu 		if (ret < 0)
820613f050dSMasami Hiramatsu 			break;
82163a29613SRavi Bangoria 		tevs[i].point.module =
82263a29613SRavi Bangoria 			strdup(mod_name ? mod_name : module);
82314a8fd7cSMasami Hiramatsu 		if (!tevs[i].point.module) {
82414a8fd7cSMasami Hiramatsu 			ret = -ENOMEM;
82514a8fd7cSMasami Hiramatsu 			break;
826190b57fcSMasami Hiramatsu 		}
82714a8fd7cSMasami Hiramatsu 	}
82814a8fd7cSMasami Hiramatsu 
82963a29613SRavi Bangoria 	free(mod_name);
830613f050dSMasami Hiramatsu 	map__put(map);
831613f050dSMasami Hiramatsu 
83214a8fd7cSMasami Hiramatsu 	return ret;
833190b57fcSMasami Hiramatsu }
834190b57fcSMasami Hiramatsu 
835d820456dSRavi Bangoria static int
836d820456dSRavi Bangoria post_process_kernel_probe_trace_events(struct probe_trace_event *tevs,
837d820456dSRavi Bangoria 				       int ntevs)
838dfef99cdSMasami Hiramatsu {
839dfef99cdSMasami Hiramatsu 	struct ref_reloc_sym *reloc_sym;
84080526491SMasami Hiramatsu 	struct map *map;
841dfef99cdSMasami Hiramatsu 	char *tmp;
8425a51fcd1SMasami Hiramatsu 	int i, skipped = 0;
843dfef99cdSMasami Hiramatsu 
844428aff82SMasami Hiramatsu 	/* Skip post process if the target is an offline kernel */
845428aff82SMasami Hiramatsu 	if (symbol_conf.ignore_vmlinux_buildid)
8468a937a25SMasami Hiramatsu 		return post_process_offline_probe_trace_events(tevs, ntevs,
8478a937a25SMasami Hiramatsu 						symbol_conf.vmlinux_name);
848428aff82SMasami Hiramatsu 
84980526491SMasami Hiramatsu 	reloc_sym = kernel_get_ref_reloc_sym(&map);
850dfef99cdSMasami Hiramatsu 	if (!reloc_sym) {
85141ca1d1eSRavi Bangoria 		pr_warning("Relocated base symbol is not found! "
85241ca1d1eSRavi Bangoria 			   "Check /proc/sys/kernel/kptr_restrict\n"
85341ca1d1eSRavi Bangoria 			   "and /proc/sys/kernel/perf_event_paranoid. "
85441ca1d1eSRavi Bangoria 			   "Or run as privileged perf user.\n\n");
855dfef99cdSMasami Hiramatsu 		return -EINVAL;
856dfef99cdSMasami Hiramatsu 	}
857dfef99cdSMasami Hiramatsu 
858dfef99cdSMasami Hiramatsu 	for (i = 0; i < ntevs; i++) {
8597ab31d94SNaveen N. Rao 		if (!tevs[i].point.address)
8607ab31d94SNaveen N. Rao 			continue;
8617ab31d94SNaveen N. Rao 		if (tevs[i].point.retprobe && !kretprobe_offset_is_supported())
862b031220dSMasami Hiramatsu 			continue;
86380526491SMasami Hiramatsu 		/*
86480526491SMasami Hiramatsu 		 * If we found a wrong one, mark it by NULL symbol.
86580526491SMasami Hiramatsu 		 * Since addresses in debuginfo is same as objdump, we need
86680526491SMasami Hiramatsu 		 * to convert it to addresses on memory.
86780526491SMasami Hiramatsu 		 */
868b031220dSMasami Hiramatsu 		if (kprobe_warn_out_range(tevs[i].point.symbol,
86980526491SMasami Hiramatsu 			map__objdump_2mem(map, tevs[i].point.address))) {
8705a51fcd1SMasami Hiramatsu 			tmp = NULL;
8715a51fcd1SMasami Hiramatsu 			skipped++;
8725a51fcd1SMasami Hiramatsu 		} else {
873dfef99cdSMasami Hiramatsu 			tmp = strdup(reloc_sym->name);
874dfef99cdSMasami Hiramatsu 			if (!tmp)
875dfef99cdSMasami Hiramatsu 				return -ENOMEM;
8765a51fcd1SMasami Hiramatsu 		}
8774c859351SMasami Hiramatsu 		/* If we have no realname, use symbol for it */
8784c859351SMasami Hiramatsu 		if (!tevs[i].point.realname)
8794c859351SMasami Hiramatsu 			tevs[i].point.realname = tevs[i].point.symbol;
8804c859351SMasami Hiramatsu 		else
881dfef99cdSMasami Hiramatsu 			free(tevs[i].point.symbol);
882dfef99cdSMasami Hiramatsu 		tevs[i].point.symbol = tmp;
883dfef99cdSMasami Hiramatsu 		tevs[i].point.offset = tevs[i].point.address -
8842a6e5e8aSIan Rogers 			(map__reloc(map) ? reloc_sym->unrelocated_addr :
885ac7a75d1SMasami Hiramatsu 				      reloc_sym->addr);
886dfef99cdSMasami Hiramatsu 	}
8875a51fcd1SMasami Hiramatsu 	return skipped;
888dfef99cdSMasami Hiramatsu }
889dfef99cdSMasami Hiramatsu 
89099e608b5SRavi Bangoria void __weak
89199e608b5SRavi Bangoria arch__post_process_probe_trace_events(struct perf_probe_event *pev __maybe_unused,
89299e608b5SRavi Bangoria 				      int ntevs __maybe_unused)
89399e608b5SRavi Bangoria {
89499e608b5SRavi Bangoria }
89599e608b5SRavi Bangoria 
896d820456dSRavi Bangoria /* Post processing the probe events */
89799e608b5SRavi Bangoria static int post_process_probe_trace_events(struct perf_probe_event *pev,
89899e608b5SRavi Bangoria 					   struct probe_trace_event *tevs,
899d820456dSRavi Bangoria 					   int ntevs, const char *module,
900613f050dSMasami Hiramatsu 					   bool uprobe, struct debuginfo *dinfo)
901d820456dSRavi Bangoria {
90299e608b5SRavi Bangoria 	int ret;
90399e608b5SRavi Bangoria 
904d820456dSRavi Bangoria 	if (uprobe)
905544abd44SKrister Johansen 		ret = add_exec_to_probe_trace_events(tevs, ntevs, module,
906544abd44SKrister Johansen 						     pev->nsi);
90799e608b5SRavi Bangoria 	else if (module)
908d820456dSRavi Bangoria 		/* Currently ref_reloc_sym based probe is not for drivers */
909613f050dSMasami Hiramatsu 		ret = post_process_module_probe_trace_events(tevs, ntevs,
910613f050dSMasami Hiramatsu 							     module, dinfo);
91199e608b5SRavi Bangoria 	else
91299e608b5SRavi Bangoria 		ret = post_process_kernel_probe_trace_events(tevs, ntevs);
913d820456dSRavi Bangoria 
91499e608b5SRavi Bangoria 	if (ret >= 0)
91599e608b5SRavi Bangoria 		arch__post_process_probe_trace_events(pev, ntevs);
91699e608b5SRavi Bangoria 
91799e608b5SRavi Bangoria 	return ret;
918d820456dSRavi Bangoria }
919d820456dSRavi Bangoria 
9204b4da7f7SMasami Hiramatsu /* Try to find perf_probe_event with debuginfo */
9210e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
922ddb2f58fSMasami Hiramatsu 					  struct probe_trace_event **tevs)
9234b4da7f7SMasami Hiramatsu {
9244b4da7f7SMasami Hiramatsu 	bool need_dwarf = perf_probe_event_need_dwarf(pev);
9259b118acaSMasami Hiramatsu 	struct perf_probe_point tmp;
926225466f1SSrikar Dronamraju 	struct debuginfo *dinfo;
927190b57fcSMasami Hiramatsu 	int ntevs, ret = 0;
9284b4da7f7SMasami Hiramatsu 
929105f75ebSJianlin Lv 	/* Workaround for gcc #98776 issue.
930105f75ebSJianlin Lv 	 * Perf failed to add kretprobe event with debuginfo of vmlinux which is
931105f75ebSJianlin Lv 	 * compiled by gcc with -fpatchable-function-entry option enabled. The
932105f75ebSJianlin Lv 	 * same issue with kernel module. The retprobe doesn`t need debuginfo.
933105f75ebSJianlin Lv 	 * This workaround solution use map to query the probe function address
934105f75ebSJianlin Lv 	 * for retprobe event.
935105f75ebSJianlin Lv 	 */
936105f75ebSJianlin Lv 	if (pev->point.retprobe)
937105f75ebSJianlin Lv 		return 0;
938105f75ebSJianlin Lv 
939544abd44SKrister Johansen 	dinfo = open_debuginfo(pev->target, pev->nsi, !need_dwarf);
940ff741783SMasami Hiramatsu 	if (!dinfo) {
94192561cb7SMasami Hiramatsu 		if (need_dwarf)
94267ef66baSAthira Rajeev 			return -ENODATA;
943ff741783SMasami Hiramatsu 		pr_debug("Could not open debuginfo. Try to use symbols.\n");
9444b4da7f7SMasami Hiramatsu 		return 0;
9454b4da7f7SMasami Hiramatsu 	}
9464b4da7f7SMasami Hiramatsu 
947dfef99cdSMasami Hiramatsu 	pr_debug("Try to find probe point from debuginfo.\n");
948ff741783SMasami Hiramatsu 	/* Searching trace events corresponding to a probe event */
949ddb2f58fSMasami Hiramatsu 	ntevs = debuginfo__find_trace_events(dinfo, pev, tevs);
950ff741783SMasami Hiramatsu 
9519b118acaSMasami Hiramatsu 	if (ntevs == 0)	{  /* Not found, retry with an alternative */
95244225521SMasami Hiramatsu 		ret = get_alternative_probe_event(dinfo, pev, &tmp);
9539b118acaSMasami Hiramatsu 		if (!ret) {
954ddb2f58fSMasami Hiramatsu 			ntevs = debuginfo__find_trace_events(dinfo, pev, tevs);
9559b118acaSMasami Hiramatsu 			/*
9569b118acaSMasami Hiramatsu 			 * Write back to the original probe_event for
9579b118acaSMasami Hiramatsu 			 * setting appropriate (user given) event name
9589b118acaSMasami Hiramatsu 			 */
9599b118acaSMasami Hiramatsu 			clear_perf_probe_point(&pev->point);
9609b118acaSMasami Hiramatsu 			memcpy(&pev->point, &tmp, sizeof(tmp));
9619b118acaSMasami Hiramatsu 		}
9629b118acaSMasami Hiramatsu 	}
9639b118acaSMasami Hiramatsu 
964146a1439SMasami Hiramatsu 	if (ntevs > 0) {	/* Succeeded to find trace events */
965dfef99cdSMasami Hiramatsu 		pr_debug("Found %d probe_trace_events.\n", ntevs);
96699e608b5SRavi Bangoria 		ret = post_process_probe_trace_events(pev, *tevs, ntevs,
967613f050dSMasami Hiramatsu 					pev->target, pev->uprobes, dinfo);
9685a51fcd1SMasami Hiramatsu 		if (ret < 0 || ret == ntevs) {
969613f050dSMasami Hiramatsu 			pr_debug("Post processing failed or all events are skipped. (%d)\n", ret);
970981d05adSMasami Hiramatsu 			clear_probe_trace_events(*tevs, ntevs);
971981d05adSMasami Hiramatsu 			zfree(tevs);
9725a51fcd1SMasami Hiramatsu 			ntevs = 0;
973146a1439SMasami Hiramatsu 		}
974613f050dSMasami Hiramatsu 	}
975613f050dSMasami Hiramatsu 
976613f050dSMasami Hiramatsu 	debuginfo__delete(dinfo);
9774b4da7f7SMasami Hiramatsu 
978146a1439SMasami Hiramatsu 	if (ntevs == 0)	{	/* No error but failed to find probe point. */
9797bc0153cSArnaldo Carvalho de Melo 		char *probe_point = synthesize_perf_probe_point(&pev->point);
9807bc0153cSArnaldo Carvalho de Melo 		pr_warning("Probe point '%s' not found.\n", probe_point);
9817bc0153cSArnaldo Carvalho de Melo 		free(probe_point);
98267ef66baSAthira Rajeev 		return -ENODEV;
983613f050dSMasami Hiramatsu 	} else if (ntevs < 0) {
984146a1439SMasami Hiramatsu 		/* Error path : ntevs < 0 */
98515eca306SMasami Hiramatsu 		pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
9861c0bd0e8SWang Nan 		if (ntevs == -EBADF)
98715eca306SMasami Hiramatsu 			pr_warning("Warning: No dwarf info found in the vmlinux - "
98815eca306SMasami Hiramatsu 				"please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
98915eca306SMasami Hiramatsu 		if (!need_dwarf) {
9900e43e5d2SMasami Hiramatsu 			pr_debug("Trying to use symbols.\n");
9914b4da7f7SMasami Hiramatsu 			return 0;
9924b4da7f7SMasami Hiramatsu 		}
99315eca306SMasami Hiramatsu 	}
99415eca306SMasami Hiramatsu 	return ntevs;
99515eca306SMasami Hiramatsu }
9964b4da7f7SMasami Hiramatsu 
9974b4da7f7SMasami Hiramatsu #define LINEBUF_SIZE 256
9984b4da7f7SMasami Hiramatsu #define NR_ADDITIONAL_LINES 2
9994b4da7f7SMasami Hiramatsu 
1000fde52dbdSFranck Bui-Huu static int __show_one_line(FILE *fp, int l, bool skip, bool show_num)
10014b4da7f7SMasami Hiramatsu {
10025f03cba4SMasami Hiramatsu 	char buf[LINEBUF_SIZE], sbuf[STRERR_BUFSIZE];
1003befe3414SFranck Bui-Huu 	const char *color = show_num ? "" : PERF_COLOR_BLUE;
1004befe3414SFranck Bui-Huu 	const char *prefix = NULL;
10054b4da7f7SMasami Hiramatsu 
1006befe3414SFranck Bui-Huu 	do {
10074b4da7f7SMasami Hiramatsu 		if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
10084b4da7f7SMasami Hiramatsu 			goto error;
1009befe3414SFranck Bui-Huu 		if (skip)
1010befe3414SFranck Bui-Huu 			continue;
1011befe3414SFranck Bui-Huu 		if (!prefix) {
1012befe3414SFranck Bui-Huu 			prefix = show_num ? "%7d  " : "         ";
1013befe3414SFranck Bui-Huu 			color_fprintf(stdout, color, prefix, l);
10144b4da7f7SMasami Hiramatsu 		}
1015befe3414SFranck Bui-Huu 		color_fprintf(stdout, color, "%s", buf);
10164b4da7f7SMasami Hiramatsu 
1017befe3414SFranck Bui-Huu 	} while (strchr(buf, '\n') == NULL);
1018146a1439SMasami Hiramatsu 
1019fde52dbdSFranck Bui-Huu 	return 1;
10204b4da7f7SMasami Hiramatsu error:
1021fde52dbdSFranck Bui-Huu 	if (ferror(fp)) {
10225f03cba4SMasami Hiramatsu 		pr_warning("File read error: %s\n",
1023c8b5f2c9SArnaldo Carvalho de Melo 			   str_error_r(errno, sbuf, sizeof(sbuf)));
1024146a1439SMasami Hiramatsu 		return -1;
10254b4da7f7SMasami Hiramatsu 	}
1026fde52dbdSFranck Bui-Huu 	return 0;
1027fde52dbdSFranck Bui-Huu }
1028fde52dbdSFranck Bui-Huu 
1029fde52dbdSFranck Bui-Huu static int _show_one_line(FILE *fp, int l, bool skip, bool show_num)
1030fde52dbdSFranck Bui-Huu {
1031fde52dbdSFranck Bui-Huu 	int rv = __show_one_line(fp, l, skip, show_num);
1032fde52dbdSFranck Bui-Huu 	if (rv == 0) {
1033fde52dbdSFranck Bui-Huu 		pr_warning("Source file is shorter than expected.\n");
1034fde52dbdSFranck Bui-Huu 		rv = -1;
1035fde52dbdSFranck Bui-Huu 	}
1036fde52dbdSFranck Bui-Huu 	return rv;
1037fde52dbdSFranck Bui-Huu }
1038fde52dbdSFranck Bui-Huu 
1039fde52dbdSFranck Bui-Huu #define show_one_line_with_num(f,l)	_show_one_line(f,l,false,true)
1040fde52dbdSFranck Bui-Huu #define show_one_line(f,l)		_show_one_line(f,l,false,false)
1041fde52dbdSFranck Bui-Huu #define skip_one_line(f,l)		_show_one_line(f,l,true,false)
1042fde52dbdSFranck Bui-Huu #define show_one_line_or_eof(f,l)	__show_one_line(f,l,false,false)
10434b4da7f7SMasami Hiramatsu 
10444b4da7f7SMasami Hiramatsu /*
10454b4da7f7SMasami Hiramatsu  * Show line-range always requires debuginfo to find source file and
10464b4da7f7SMasami Hiramatsu  * line number.
10474b4da7f7SMasami Hiramatsu  */
1048811dd2aeSMasami Hiramatsu static int __show_line_range(struct line_range *lr, const char *module,
1049811dd2aeSMasami Hiramatsu 			     bool user)
10504b4da7f7SMasami Hiramatsu {
1051bf541169SJiri Olsa 	struct build_id bid;
1052d3b63d7aSMasami Hiramatsu 	int l = 1;
10535a62257aSMasami Hiramatsu 	struct int_node *ln;
1054ff741783SMasami Hiramatsu 	struct debuginfo *dinfo;
10554b4da7f7SMasami Hiramatsu 	FILE *fp;
1056ff741783SMasami Hiramatsu 	int ret;
10577cf0b79eSMasami Hiramatsu 	char *tmp;
10585f03cba4SMasami Hiramatsu 	char sbuf[STRERR_BUFSIZE];
10597cd5738dSMasami Hiramatsu 	char sbuild_id[SBUILD_ID_SIZE] = "";
10604b4da7f7SMasami Hiramatsu 
10614b4da7f7SMasami Hiramatsu 	/* Search a line range */
1062544abd44SKrister Johansen 	dinfo = open_debuginfo(module, NULL, false);
106392561cb7SMasami Hiramatsu 	if (!dinfo)
1064ff741783SMasami Hiramatsu 		return -ENOENT;
1065146a1439SMasami Hiramatsu 
1066ff741783SMasami Hiramatsu 	ret = debuginfo__find_line_range(dinfo, lr);
1067811dd2aeSMasami Hiramatsu 	if (!ret) {	/* Not found, retry with an alternative */
1068811dd2aeSMasami Hiramatsu 		ret = get_alternative_line_range(dinfo, lr, module, user);
1069811dd2aeSMasami Hiramatsu 		if (!ret)
1070811dd2aeSMasami Hiramatsu 			ret = debuginfo__find_line_range(dinfo, lr);
1071811dd2aeSMasami Hiramatsu 	}
1072bf541169SJiri Olsa 	if (dinfo->build_id) {
1073bf541169SJiri Olsa 		build_id__init(&bid, dinfo->build_id, BUILD_ID_SIZE);
1074bf541169SJiri Olsa 		build_id__sprintf(&bid, sbuild_id);
1075bf541169SJiri Olsa 	}
1076ff741783SMasami Hiramatsu 	debuginfo__delete(dinfo);
10775ee05b88SMasami Hiramatsu 	if (ret == 0 || ret == -ENOENT) {
1078146a1439SMasami Hiramatsu 		pr_warning("Specified source line is not found.\n");
1079146a1439SMasami Hiramatsu 		return -ENOENT;
1080146a1439SMasami Hiramatsu 	} else if (ret < 0) {
10815ee05b88SMasami Hiramatsu 		pr_warning("Debuginfo analysis failed.\n");
1082146a1439SMasami Hiramatsu 		return ret;
1083146a1439SMasami Hiramatsu 	}
10844b4da7f7SMasami Hiramatsu 
10857cf0b79eSMasami Hiramatsu 	/* Convert source file path */
10867cf0b79eSMasami Hiramatsu 	tmp = lr->path;
10877cd5738dSMasami Hiramatsu 	ret = find_source_path(tmp, sbuild_id, lr->comp_dir, &lr->path);
1088a78604deSHe Kuang 
1089a78604deSHe Kuang 	/* Free old path when new path is assigned */
1090a78604deSHe Kuang 	if (tmp != lr->path)
1091a78604deSHe Kuang 		free(tmp);
1092a78604deSHe Kuang 
10937cf0b79eSMasami Hiramatsu 	if (ret < 0) {
10945ee05b88SMasami Hiramatsu 		pr_warning("Failed to find source file path.\n");
10957cf0b79eSMasami Hiramatsu 		return ret;
10967cf0b79eSMasami Hiramatsu 	}
10977cf0b79eSMasami Hiramatsu 
10984b4da7f7SMasami Hiramatsu 	setup_pager();
10994b4da7f7SMasami Hiramatsu 
11004b4da7f7SMasami Hiramatsu 	if (lr->function)
11018737ebdeSMasami Hiramatsu 		fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path,
11024b4da7f7SMasami Hiramatsu 			lr->start - lr->offset);
11034b4da7f7SMasami Hiramatsu 	else
110462c15fc4SFranck Bui-Huu 		fprintf(stdout, "<%s:%d>\n", lr->path, lr->start);
11054b4da7f7SMasami Hiramatsu 
11064b4da7f7SMasami Hiramatsu 	fp = fopen(lr->path, "r");
1107146a1439SMasami Hiramatsu 	if (fp == NULL) {
1108146a1439SMasami Hiramatsu 		pr_warning("Failed to open %s: %s\n", lr->path,
1109c8b5f2c9SArnaldo Carvalho de Melo 			   str_error_r(errno, sbuf, sizeof(sbuf)));
1110146a1439SMasami Hiramatsu 		return -errno;
1111146a1439SMasami Hiramatsu 	}
11124b4da7f7SMasami Hiramatsu 	/* Skip to starting line number */
111344b81e92SFranck Bui-Huu 	while (l < lr->start) {
1114fde52dbdSFranck Bui-Huu 		ret = skip_one_line(fp, l++);
1115146a1439SMasami Hiramatsu 		if (ret < 0)
1116146a1439SMasami Hiramatsu 			goto end;
111744b81e92SFranck Bui-Huu 	}
11184b4da7f7SMasami Hiramatsu 
111910daf4d0SArnaldo Carvalho de Melo 	intlist__for_each_entry(ln, lr->line_list) {
112094253393SJin Yao 		for (; ln->i > (unsigned long)l; l++) {
1121fde52dbdSFranck Bui-Huu 			ret = show_one_line(fp, l - lr->offset);
112244b81e92SFranck Bui-Huu 			if (ret < 0)
112344b81e92SFranck Bui-Huu 				goto end;
112444b81e92SFranck Bui-Huu 		}
1125fde52dbdSFranck Bui-Huu 		ret = show_one_line_with_num(fp, l++ - lr->offset);
1126146a1439SMasami Hiramatsu 		if (ret < 0)
1127146a1439SMasami Hiramatsu 			goto end;
11284b4da7f7SMasami Hiramatsu 	}
11294b4da7f7SMasami Hiramatsu 
11304b4da7f7SMasami Hiramatsu 	if (lr->end == INT_MAX)
11314b4da7f7SMasami Hiramatsu 		lr->end = l + NR_ADDITIONAL_LINES;
1132fde52dbdSFranck Bui-Huu 	while (l <= lr->end) {
1133fde52dbdSFranck Bui-Huu 		ret = show_one_line_or_eof(fp, l++ - lr->offset);
1134fde52dbdSFranck Bui-Huu 		if (ret <= 0)
113544b81e92SFranck Bui-Huu 			break;
113644b81e92SFranck Bui-Huu 	}
1137146a1439SMasami Hiramatsu end:
11384b4da7f7SMasami Hiramatsu 	fclose(fp);
1139146a1439SMasami Hiramatsu 	return ret;
11404b4da7f7SMasami Hiramatsu }
11414b4da7f7SMasami Hiramatsu 
1142544abd44SKrister Johansen int show_line_range(struct line_range *lr, const char *module,
1143544abd44SKrister Johansen 		    struct nsinfo *nsi, bool user)
1144ee45b6c2SMasami Hiramatsu {
1145ee45b6c2SMasami Hiramatsu 	int ret;
1146544abd44SKrister Johansen 	struct nscookie nsc;
1147ee45b6c2SMasami Hiramatsu 
11489bae1e8cSNamhyung Kim 	ret = init_probe_symbol_maps(user);
1149ee45b6c2SMasami Hiramatsu 	if (ret < 0)
1150ee45b6c2SMasami Hiramatsu 		return ret;
1151544abd44SKrister Johansen 	nsinfo__mountns_enter(nsi, &nsc);
1152811dd2aeSMasami Hiramatsu 	ret = __show_line_range(lr, module, user);
1153544abd44SKrister Johansen 	nsinfo__mountns_exit(&nsc);
11549bae1e8cSNamhyung Kim 	exit_probe_symbol_maps();
1155ee45b6c2SMasami Hiramatsu 
1156ee45b6c2SMasami Hiramatsu 	return ret;
1157ee45b6c2SMasami Hiramatsu }
1158ee45b6c2SMasami Hiramatsu 
1159ff741783SMasami Hiramatsu static int show_available_vars_at(struct debuginfo *dinfo,
1160ff741783SMasami Hiramatsu 				  struct perf_probe_event *pev,
1161ddb2f58fSMasami Hiramatsu 				  struct strfilter *_filter)
1162cf6eb489SMasami Hiramatsu {
1163cf6eb489SMasami Hiramatsu 	char *buf;
1164bd09d7b5SMasami Hiramatsu 	int ret, i, nvars;
1165cf6eb489SMasami Hiramatsu 	struct str_node *node;
1166cf6eb489SMasami Hiramatsu 	struct variable_list *vls = NULL, *vl;
11679b118acaSMasami Hiramatsu 	struct perf_probe_point tmp;
1168bd09d7b5SMasami Hiramatsu 	const char *var;
1169cf6eb489SMasami Hiramatsu 
1170cf6eb489SMasami Hiramatsu 	buf = synthesize_perf_probe_point(&pev->point);
1171cf6eb489SMasami Hiramatsu 	if (!buf)
1172cf6eb489SMasami Hiramatsu 		return -EINVAL;
1173cf6eb489SMasami Hiramatsu 	pr_debug("Searching variables at %s\n", buf);
1174cf6eb489SMasami Hiramatsu 
1175ddb2f58fSMasami Hiramatsu 	ret = debuginfo__find_available_vars_at(dinfo, pev, &vls);
11769b118acaSMasami Hiramatsu 	if (!ret) {  /* Not found, retry with an alternative */
117744225521SMasami Hiramatsu 		ret = get_alternative_probe_event(dinfo, pev, &tmp);
11789b118acaSMasami Hiramatsu 		if (!ret) {
11799b118acaSMasami Hiramatsu 			ret = debuginfo__find_available_vars_at(dinfo, pev,
1180ddb2f58fSMasami Hiramatsu 								&vls);
11819b118acaSMasami Hiramatsu 			/* Release the old probe_point */
11829b118acaSMasami Hiramatsu 			clear_perf_probe_point(&tmp);
11839b118acaSMasami Hiramatsu 		}
11849b118acaSMasami Hiramatsu 	}
1185bd09d7b5SMasami Hiramatsu 	if (ret <= 0) {
118669e96eaaSMasami Hiramatsu 		if (ret == 0 || ret == -ENOENT) {
118769e96eaaSMasami Hiramatsu 			pr_err("Failed to find the address of %s\n", buf);
118869e96eaaSMasami Hiramatsu 			ret = -ENOENT;
118969e96eaaSMasami Hiramatsu 		} else
119069e96eaaSMasami Hiramatsu 			pr_warning("Debuginfo analysis failed.\n");
1191bd09d7b5SMasami Hiramatsu 		goto end;
1192bd09d7b5SMasami Hiramatsu 	}
119369e96eaaSMasami Hiramatsu 
1194bd09d7b5SMasami Hiramatsu 	/* Some variables are found */
1195cf6eb489SMasami Hiramatsu 	fprintf(stdout, "Available variables at %s\n", buf);
1196cf6eb489SMasami Hiramatsu 	for (i = 0; i < ret; i++) {
1197cf6eb489SMasami Hiramatsu 		vl = &vls[i];
1198cf6eb489SMasami Hiramatsu 		/*
1199cf6eb489SMasami Hiramatsu 		 * A probe point might be converted to
1200cf6eb489SMasami Hiramatsu 		 * several trace points.
1201cf6eb489SMasami Hiramatsu 		 */
1202cf6eb489SMasami Hiramatsu 		fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
1203cf6eb489SMasami Hiramatsu 			vl->point.offset);
120474cf249dSArnaldo Carvalho de Melo 		zfree(&vl->point.symbol);
1205bd09d7b5SMasami Hiramatsu 		nvars = 0;
1206cf6eb489SMasami Hiramatsu 		if (vl->vars) {
1207602a1f4dSArnaldo Carvalho de Melo 			strlist__for_each_entry(node, vl->vars) {
1208bd09d7b5SMasami Hiramatsu 				var = strchr(node->s, '\t') + 1;
1209bd09d7b5SMasami Hiramatsu 				if (strfilter__compare(_filter, var)) {
1210cf6eb489SMasami Hiramatsu 					fprintf(stdout, "\t\t%s\n", node->s);
1211bd09d7b5SMasami Hiramatsu 					nvars++;
1212bd09d7b5SMasami Hiramatsu 				}
1213bd09d7b5SMasami Hiramatsu 			}
1214cf6eb489SMasami Hiramatsu 			strlist__delete(vl->vars);
1215bd09d7b5SMasami Hiramatsu 		}
1216bd09d7b5SMasami Hiramatsu 		if (nvars == 0)
1217bd09d7b5SMasami Hiramatsu 			fprintf(stdout, "\t\t(No matched variables)\n");
1218cf6eb489SMasami Hiramatsu 	}
1219cf6eb489SMasami Hiramatsu 	free(vls);
1220bd09d7b5SMasami Hiramatsu end:
1221cf6eb489SMasami Hiramatsu 	free(buf);
1222cf6eb489SMasami Hiramatsu 	return ret;
1223cf6eb489SMasami Hiramatsu }
1224cf6eb489SMasami Hiramatsu 
1225cf6eb489SMasami Hiramatsu /* Show available variables on given probe point */
1226cf6eb489SMasami Hiramatsu int show_available_vars(struct perf_probe_event *pevs, int npevs,
1227ddb2f58fSMasami Hiramatsu 			struct strfilter *_filter)
1228cf6eb489SMasami Hiramatsu {
1229ff741783SMasami Hiramatsu 	int i, ret = 0;
1230ff741783SMasami Hiramatsu 	struct debuginfo *dinfo;
1231cf6eb489SMasami Hiramatsu 
12329bae1e8cSNamhyung Kim 	ret = init_probe_symbol_maps(pevs->uprobes);
1233cf6eb489SMasami Hiramatsu 	if (ret < 0)
1234cf6eb489SMasami Hiramatsu 		return ret;
1235cf6eb489SMasami Hiramatsu 
1236544abd44SKrister Johansen 	dinfo = open_debuginfo(pevs->target, pevs->nsi, false);
1237ff741783SMasami Hiramatsu 	if (!dinfo) {
1238ee45b6c2SMasami Hiramatsu 		ret = -ENOENT;
1239ee45b6c2SMasami Hiramatsu 		goto out;
1240ff741783SMasami Hiramatsu 	}
1241ff741783SMasami Hiramatsu 
1242cc446446SMasami Hiramatsu 	setup_pager();
1243cc446446SMasami Hiramatsu 
1244ff741783SMasami Hiramatsu 	for (i = 0; i < npevs && ret >= 0; i++)
1245ddb2f58fSMasami Hiramatsu 		ret = show_available_vars_at(dinfo, &pevs[i], _filter);
1246ff741783SMasami Hiramatsu 
1247ff741783SMasami Hiramatsu 	debuginfo__delete(dinfo);
1248ee45b6c2SMasami Hiramatsu out:
12499bae1e8cSNamhyung Kim 	exit_probe_symbol_maps();
1250cf6eb489SMasami Hiramatsu 	return ret;
1251cf6eb489SMasami Hiramatsu }
1252cf6eb489SMasami Hiramatsu 
125389fe808aSIngo Molnar #else	/* !HAVE_DWARF_SUPPORT */
12544b4da7f7SMasami Hiramatsu 
12557737af01SMasami Hiramatsu static void debuginfo_cache__exit(void)
12567737af01SMasami Hiramatsu {
12577737af01SMasami Hiramatsu }
12587737af01SMasami Hiramatsu 
12595a6f6314SMasami Hiramatsu static int
12605a6f6314SMasami Hiramatsu find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused,
12615a6f6314SMasami Hiramatsu 				 struct perf_probe_point *pp __maybe_unused,
12625a6f6314SMasami Hiramatsu 				 bool is_kprobe __maybe_unused)
12634b4da7f7SMasami Hiramatsu {
12645a6f6314SMasami Hiramatsu 	return -ENOSYS;
12654b4da7f7SMasami Hiramatsu }
12664b4da7f7SMasami Hiramatsu 
12670e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
1268ddb2f58fSMasami Hiramatsu 				struct probe_trace_event **tevs __maybe_unused)
12694b4da7f7SMasami Hiramatsu {
1270146a1439SMasami Hiramatsu 	if (perf_probe_event_need_dwarf(pev)) {
1271146a1439SMasami Hiramatsu 		pr_warning("Debuginfo-analysis is not supported.\n");
1272146a1439SMasami Hiramatsu 		return -ENOSYS;
1273146a1439SMasami Hiramatsu 	}
1274225466f1SSrikar Dronamraju 
12754b4da7f7SMasami Hiramatsu 	return 0;
12764b4da7f7SMasami Hiramatsu }
12774b4da7f7SMasami Hiramatsu 
12781d037ca1SIrina Tirdea int show_line_range(struct line_range *lr __maybe_unused,
12792b394bc4SMasami Hiramatsu 		    const char *module __maybe_unused,
1280544abd44SKrister Johansen 		    struct nsinfo *nsi __maybe_unused,
12812b394bc4SMasami Hiramatsu 		    bool user __maybe_unused)
12824b4da7f7SMasami Hiramatsu {
1283146a1439SMasami Hiramatsu 	pr_warning("Debuginfo-analysis is not supported.\n");
1284146a1439SMasami Hiramatsu 	return -ENOSYS;
12854b4da7f7SMasami Hiramatsu }
12864b4da7f7SMasami Hiramatsu 
12871d037ca1SIrina Tirdea int show_available_vars(struct perf_probe_event *pevs __maybe_unused,
1288ddb2f58fSMasami Hiramatsu 			int npevs __maybe_unused,
1289ddb2f58fSMasami Hiramatsu 			struct strfilter *filter __maybe_unused)
1290cf6eb489SMasami Hiramatsu {
1291cf6eb489SMasami Hiramatsu 	pr_warning("Debuginfo-analysis is not supported.\n");
1292cf6eb489SMasami Hiramatsu 	return -ENOSYS;
1293cf6eb489SMasami Hiramatsu }
1294e0faa8d3SMasami Hiramatsu #endif
1295e0faa8d3SMasami Hiramatsu 
1296e53b00d3SMasami Hiramatsu void line_range__clear(struct line_range *lr)
1297e53b00d3SMasami Hiramatsu {
1298d8f9da24SArnaldo Carvalho de Melo 	zfree(&lr->function);
1299d8f9da24SArnaldo Carvalho de Melo 	zfree(&lr->file);
1300d8f9da24SArnaldo Carvalho de Melo 	zfree(&lr->path);
1301d8f9da24SArnaldo Carvalho de Melo 	zfree(&lr->comp_dir);
13025a62257aSMasami Hiramatsu 	intlist__delete(lr->line_list);
1303e53b00d3SMasami Hiramatsu }
1304e53b00d3SMasami Hiramatsu 
13055a62257aSMasami Hiramatsu int line_range__init(struct line_range *lr)
1306e53b00d3SMasami Hiramatsu {
1307e53b00d3SMasami Hiramatsu 	memset(lr, 0, sizeof(*lr));
13085a62257aSMasami Hiramatsu 	lr->line_list = intlist__new(NULL);
13095a62257aSMasami Hiramatsu 	if (!lr->line_list)
13105a62257aSMasami Hiramatsu 		return -ENOMEM;
13115a62257aSMasami Hiramatsu 	else
13125a62257aSMasami Hiramatsu 		return 0;
1313e53b00d3SMasami Hiramatsu }
1314e53b00d3SMasami Hiramatsu 
131521dd9ae5SFranck Bui-Huu static int parse_line_num(char **ptr, int *val, const char *what)
131621dd9ae5SFranck Bui-Huu {
131721dd9ae5SFranck Bui-Huu 	const char *start = *ptr;
131821dd9ae5SFranck Bui-Huu 
131921dd9ae5SFranck Bui-Huu 	errno = 0;
132021dd9ae5SFranck Bui-Huu 	*val = strtol(*ptr, ptr, 0);
132121dd9ae5SFranck Bui-Huu 	if (errno || *ptr == start) {
132221dd9ae5SFranck Bui-Huu 		semantic_error("'%s' is not a valid number.\n", what);
132321dd9ae5SFranck Bui-Huu 		return -EINVAL;
132421dd9ae5SFranck Bui-Huu 	}
132521dd9ae5SFranck Bui-Huu 	return 0;
132621dd9ae5SFranck Bui-Huu }
132721dd9ae5SFranck Bui-Huu 
1328573709fdSMasami Hiramatsu /* Check the name is good for event, group or function */
1329573709fdSMasami Hiramatsu static bool is_c_func_name(const char *name)
1330573709fdSMasami Hiramatsu {
1331573709fdSMasami Hiramatsu 	if (!isalpha(*name) && *name != '_')
1332573709fdSMasami Hiramatsu 		return false;
1333573709fdSMasami Hiramatsu 	while (*++name != '\0') {
1334573709fdSMasami Hiramatsu 		if (!isalpha(*name) && !isdigit(*name) && *name != '_')
1335573709fdSMasami Hiramatsu 			return false;
1336573709fdSMasami Hiramatsu 	}
1337573709fdSMasami Hiramatsu 	return true;
1338573709fdSMasami Hiramatsu }
1339573709fdSMasami Hiramatsu 
13409d95b580SFranck Bui-Huu /*
13419d95b580SFranck Bui-Huu  * Stuff 'lr' according to the line range described by 'arg'.
13429d95b580SFranck Bui-Huu  * The line range syntax is described by:
13439d95b580SFranck Bui-Huu  *
13449d95b580SFranck Bui-Huu  *         SRC[:SLN[+NUM|-ELN]]
1345e116dfa1SMasami Hiramatsu  *         FNC[@SRC][:SLN[+NUM|-ELN]]
13469d95b580SFranck Bui-Huu  */
1347146a1439SMasami Hiramatsu int parse_line_range_desc(const char *arg, struct line_range *lr)
1348631c9defSMasami Hiramatsu {
1349e116dfa1SMasami Hiramatsu 	char *range, *file, *name = strdup(arg);
135021dd9ae5SFranck Bui-Huu 	int err;
13519d95b580SFranck Bui-Huu 
135221dd9ae5SFranck Bui-Huu 	if (!name)
135321dd9ae5SFranck Bui-Huu 		return -ENOMEM;
135421dd9ae5SFranck Bui-Huu 
135521dd9ae5SFranck Bui-Huu 	lr->start = 0;
135621dd9ae5SFranck Bui-Huu 	lr->end = INT_MAX;
135721dd9ae5SFranck Bui-Huu 
135821dd9ae5SFranck Bui-Huu 	range = strchr(name, ':');
135921dd9ae5SFranck Bui-Huu 	if (range) {
136021dd9ae5SFranck Bui-Huu 		*range++ = '\0';
136121dd9ae5SFranck Bui-Huu 
136221dd9ae5SFranck Bui-Huu 		err = parse_line_num(&range, &lr->start, "start line");
136321dd9ae5SFranck Bui-Huu 		if (err)
136421dd9ae5SFranck Bui-Huu 			goto err;
136521dd9ae5SFranck Bui-Huu 
136621dd9ae5SFranck Bui-Huu 		if (*range == '+' || *range == '-') {
136721dd9ae5SFranck Bui-Huu 			const char c = *range++;
136821dd9ae5SFranck Bui-Huu 
136921dd9ae5SFranck Bui-Huu 			err = parse_line_num(&range, &lr->end, "end line");
137021dd9ae5SFranck Bui-Huu 			if (err)
137121dd9ae5SFranck Bui-Huu 				goto err;
137221dd9ae5SFranck Bui-Huu 
137321dd9ae5SFranck Bui-Huu 			if (c == '+') {
137421dd9ae5SFranck Bui-Huu 				lr->end += lr->start;
137521dd9ae5SFranck Bui-Huu 				/*
1376dda4ab34SMasami Hiramatsu 				 * Adjust the number of lines here.
1377dda4ab34SMasami Hiramatsu 				 * If the number of lines == 1, the
1378c69d33ebSJason Wang 				 * end of line should be equal to
1379dda4ab34SMasami Hiramatsu 				 * the start of line.
1380dda4ab34SMasami Hiramatsu 				 */
138121dd9ae5SFranck Bui-Huu 				lr->end--;
138221dd9ae5SFranck Bui-Huu 			}
138321dd9ae5SFranck Bui-Huu 		}
138421dd9ae5SFranck Bui-Huu 
1385d3b63d7aSMasami Hiramatsu 		pr_debug("Line range is %d to %d\n", lr->start, lr->end);
138621dd9ae5SFranck Bui-Huu 
138721dd9ae5SFranck Bui-Huu 		err = -EINVAL;
1388d3b63d7aSMasami Hiramatsu 		if (lr->start > lr->end) {
1389631c9defSMasami Hiramatsu 			semantic_error("Start line must be smaller"
1390146a1439SMasami Hiramatsu 				       " than end line.\n");
139121dd9ae5SFranck Bui-Huu 			goto err;
1392146a1439SMasami Hiramatsu 		}
139321dd9ae5SFranck Bui-Huu 		if (*range != '\0') {
139421dd9ae5SFranck Bui-Huu 			semantic_error("Tailing with invalid str '%s'.\n", range);
139521dd9ae5SFranck Bui-Huu 			goto err;
1396146a1439SMasami Hiramatsu 		}
1397d3b63d7aSMasami Hiramatsu 	}
139802b95dadSMasami Hiramatsu 
1399e116dfa1SMasami Hiramatsu 	file = strchr(name, '@');
1400e116dfa1SMasami Hiramatsu 	if (file) {
1401e116dfa1SMasami Hiramatsu 		*file = '\0';
1402e116dfa1SMasami Hiramatsu 		lr->file = strdup(++file);
1403e116dfa1SMasami Hiramatsu 		if (lr->file == NULL) {
1404e116dfa1SMasami Hiramatsu 			err = -ENOMEM;
1405e116dfa1SMasami Hiramatsu 			goto err;
1406e116dfa1SMasami Hiramatsu 		}
1407e116dfa1SMasami Hiramatsu 		lr->function = name;
1408573709fdSMasami Hiramatsu 	} else if (strchr(name, '/') || strchr(name, '.'))
140921dd9ae5SFranck Bui-Huu 		lr->file = name;
1410573709fdSMasami Hiramatsu 	else if (is_c_func_name(name))/* We reuse it for checking funcname */
141121dd9ae5SFranck Bui-Huu 		lr->function = name;
1412573709fdSMasami Hiramatsu 	else {	/* Invalid name */
1413573709fdSMasami Hiramatsu 		semantic_error("'%s' is not a valid function name.\n", name);
1414573709fdSMasami Hiramatsu 		err = -EINVAL;
1415573709fdSMasami Hiramatsu 		goto err;
1416573709fdSMasami Hiramatsu 	}
1417146a1439SMasami Hiramatsu 
1418146a1439SMasami Hiramatsu 	return 0;
141921dd9ae5SFranck Bui-Huu err:
142021dd9ae5SFranck Bui-Huu 	free(name);
142121dd9ae5SFranck Bui-Huu 	return err;
1422631c9defSMasami Hiramatsu }
1423631c9defSMasami Hiramatsu 
142436a009feSMasami Hiramatsu static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev)
142536a009feSMasami Hiramatsu {
142636a009feSMasami Hiramatsu 	char *ptr;
142736a009feSMasami Hiramatsu 
1428c588d158SMasami Hiramatsu 	ptr = strpbrk_esc(*arg, ":");
142936a009feSMasami Hiramatsu 	if (ptr) {
143036a009feSMasami Hiramatsu 		*ptr = '\0';
143142bba263SMasami Hiramatsu 		if (!pev->sdt && !is_c_func_name(*arg))
143236a009feSMasami Hiramatsu 			goto ng_name;
1433c588d158SMasami Hiramatsu 		pev->group = strdup_esc(*arg);
143436a009feSMasami Hiramatsu 		if (!pev->group)
143536a009feSMasami Hiramatsu 			return -ENOMEM;
143636a009feSMasami Hiramatsu 		*arg = ptr + 1;
143736a009feSMasami Hiramatsu 	} else
143836a009feSMasami Hiramatsu 		pev->group = NULL;
1439c588d158SMasami Hiramatsu 
1440c588d158SMasami Hiramatsu 	pev->event = strdup_esc(*arg);
1441c588d158SMasami Hiramatsu 	if (pev->event == NULL)
1442c588d158SMasami Hiramatsu 		return -ENOMEM;
1443c588d158SMasami Hiramatsu 
1444c588d158SMasami Hiramatsu 	if (!pev->sdt && !is_c_func_name(pev->event)) {
1445c588d158SMasami Hiramatsu 		zfree(&pev->event);
144636a009feSMasami Hiramatsu ng_name:
1447c588d158SMasami Hiramatsu 		zfree(&pev->group);
144836a009feSMasami Hiramatsu 		semantic_error("%s is bad for event name -it must "
144936a009feSMasami Hiramatsu 			       "follow C symbol-naming rule.\n", *arg);
145036a009feSMasami Hiramatsu 		return -EINVAL;
145136a009feSMasami Hiramatsu 	}
145236a009feSMasami Hiramatsu 	return 0;
145336a009feSMasami Hiramatsu }
145436a009feSMasami Hiramatsu 
145550656eecSMasami Hiramatsu /* Parse probepoint definition. */
1456146a1439SMasami Hiramatsu static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
145750656eecSMasami Hiramatsu {
14584235b045SMasami Hiramatsu 	struct perf_probe_point *pp = &pev->point;
145950656eecSMasami Hiramatsu 	char *ptr, *tmp;
146050656eecSMasami Hiramatsu 	char c, nc = 0;
14613099c026SNaveen N. Rao 	bool file_spec = false;
146236a009feSMasami Hiramatsu 	int ret;
146336a009feSMasami Hiramatsu 
146450656eecSMasami Hiramatsu 	/*
146550656eecSMasami Hiramatsu 	 * <Syntax>
14668d993d96SMasami Hiramatsu 	 * perf probe [GRP:][EVENT=]SRC[:LN|;PTN]
14678d993d96SMasami Hiramatsu 	 * perf probe [GRP:][EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
146836a009feSMasami Hiramatsu 	 * perf probe %[GRP:]SDT_EVENT
146950656eecSMasami Hiramatsu 	 */
1470e59d29e8SWang Nan 	if (!arg)
1471e59d29e8SWang Nan 		return -EINVAL;
147250656eecSMasami Hiramatsu 
1473af9100adSRavi Bangoria 	if (is_sdt_event(arg)) {
147436a009feSMasami Hiramatsu 		pev->sdt = true;
14757e9fca51SMasami Hiramatsu 		if (arg[0] == '%')
147636a009feSMasami Hiramatsu 			arg++;
147736a009feSMasami Hiramatsu 	}
147836a009feSMasami Hiramatsu 
1479c588d158SMasami Hiramatsu 	ptr = strpbrk_esc(arg, ";=@+%");
148036a009feSMasami Hiramatsu 	if (pev->sdt) {
148136a009feSMasami Hiramatsu 		if (ptr) {
1482a598180aSMasami Hiramatsu 			if (*ptr != '@') {
1483a598180aSMasami Hiramatsu 				semantic_error("%s must be an SDT name.\n",
1484a598180aSMasami Hiramatsu 					       arg);
148536a009feSMasami Hiramatsu 				return -EINVAL;
148636a009feSMasami Hiramatsu 			}
1487a598180aSMasami Hiramatsu 			/* This must be a target file name or build id */
1488a598180aSMasami Hiramatsu 			tmp = build_id_cache__complement(ptr + 1);
1489a598180aSMasami Hiramatsu 			if (tmp) {
1490a598180aSMasami Hiramatsu 				pev->target = build_id_cache__origname(tmp);
1491a598180aSMasami Hiramatsu 				free(tmp);
1492a598180aSMasami Hiramatsu 			} else
1493c588d158SMasami Hiramatsu 				pev->target = strdup_esc(ptr + 1);
1494a598180aSMasami Hiramatsu 			if (!pev->target)
1495a598180aSMasami Hiramatsu 				return -ENOMEM;
1496a598180aSMasami Hiramatsu 			*ptr = '\0';
1497a598180aSMasami Hiramatsu 		}
149836a009feSMasami Hiramatsu 		ret = parse_perf_probe_event_name(&arg, pev);
149936a009feSMasami Hiramatsu 		if (ret == 0) {
150036a009feSMasami Hiramatsu 			if (asprintf(&pev->point.function, "%%%s", pev->event) < 0)
150136a009feSMasami Hiramatsu 				ret = -errno;
150236a009feSMasami Hiramatsu 		}
150336a009feSMasami Hiramatsu 		return ret;
150436a009feSMasami Hiramatsu 	}
150536a009feSMasami Hiramatsu 
15062a9c8c36SMasami Hiramatsu 	if (ptr && *ptr == '=') {	/* Event name */
1507af663d75SMasami Hiramatsu 		*ptr = '\0';
1508af663d75SMasami Hiramatsu 		tmp = ptr + 1;
150936a009feSMasami Hiramatsu 		ret = parse_perf_probe_event_name(&arg, pev);
151036a009feSMasami Hiramatsu 		if (ret < 0)
151136a009feSMasami Hiramatsu 			return ret;
151236a009feSMasami Hiramatsu 
1513af663d75SMasami Hiramatsu 		arg = tmp;
1514af663d75SMasami Hiramatsu 	}
1515af663d75SMasami Hiramatsu 
15163099c026SNaveen N. Rao 	/*
15173099c026SNaveen N. Rao 	 * Check arg is function or file name and copy it.
15183099c026SNaveen N. Rao 	 *
15193099c026SNaveen N. Rao 	 * We consider arg to be a file spec if and only if it satisfies
15203099c026SNaveen N. Rao 	 * all of the below criteria::
15213099c026SNaveen N. Rao 	 * - it does not include any of "+@%",
15223099c026SNaveen N. Rao 	 * - it includes one of ":;", and
15233099c026SNaveen N. Rao 	 * - it has a period '.' in the name.
15243099c026SNaveen N. Rao 	 *
15253099c026SNaveen N. Rao 	 * Otherwise, we consider arg to be a function specification.
15263099c026SNaveen N. Rao 	 */
1527c588d158SMasami Hiramatsu 	if (!strpbrk_esc(arg, "+@%")) {
1528c588d158SMasami Hiramatsu 		ptr = strpbrk_esc(arg, ";:");
15293099c026SNaveen N. Rao 		/* This is a file spec if it includes a '.' before ; or : */
1530c588d158SMasami Hiramatsu 		if (ptr && memchr(arg, '.', ptr - arg))
15313099c026SNaveen N. Rao 			file_spec = true;
15323099c026SNaveen N. Rao 	}
15333099c026SNaveen N. Rao 
1534c588d158SMasami Hiramatsu 	ptr = strpbrk_esc(arg, ";:+@%");
153550656eecSMasami Hiramatsu 	if (ptr) {
153650656eecSMasami Hiramatsu 		nc = *ptr;
153750656eecSMasami Hiramatsu 		*ptr++ = '\0';
153850656eecSMasami Hiramatsu 	}
153950656eecSMasami Hiramatsu 
15406c6e024fSWang Nan 	if (arg[0] == '\0')
15416c6e024fSWang Nan 		tmp = NULL;
15426c6e024fSWang Nan 	else {
1543c588d158SMasami Hiramatsu 		tmp = strdup_esc(arg);
154402b95dadSMasami Hiramatsu 		if (tmp == NULL)
154502b95dadSMasami Hiramatsu 			return -ENOMEM;
15466c6e024fSWang Nan 	}
154702b95dadSMasami Hiramatsu 
15483099c026SNaveen N. Rao 	if (file_spec)
154902b95dadSMasami Hiramatsu 		pp->file = tmp;
1550da15bd9dSWang Nan 	else {
155102b95dadSMasami Hiramatsu 		pp->function = tmp;
155250656eecSMasami Hiramatsu 
1553da15bd9dSWang Nan 		/*
1554da15bd9dSWang Nan 		 * Keep pp->function even if this is absolute address,
1555da15bd9dSWang Nan 		 * so it can mark whether abs_address is valid.
1556da15bd9dSWang Nan 		 * Which make 'perf probe lib.bin 0x0' possible.
1557da15bd9dSWang Nan 		 *
1558da15bd9dSWang Nan 		 * Note that checking length of tmp is not needed
1559da15bd9dSWang Nan 		 * because when we access tmp[1] we know tmp[0] is '0',
1560da15bd9dSWang Nan 		 * so tmp[1] should always valid (but could be '\0').
1561da15bd9dSWang Nan 		 */
1562da15bd9dSWang Nan 		if (tmp && !strncmp(tmp, "0x", 2)) {
156322a66551SYang Jihong 			pp->abs_address = strtoull(pp->function, &tmp, 0);
1564da15bd9dSWang Nan 			if (*tmp != '\0') {
1565da15bd9dSWang Nan 				semantic_error("Invalid absolute address.\n");
1566da15bd9dSWang Nan 				return -EINVAL;
1567da15bd9dSWang Nan 			}
1568da15bd9dSWang Nan 		}
1569da15bd9dSWang Nan 	}
1570da15bd9dSWang Nan 
157150656eecSMasami Hiramatsu 	/* Parse other options */
157250656eecSMasami Hiramatsu 	while (ptr) {
157350656eecSMasami Hiramatsu 		arg = ptr;
157450656eecSMasami Hiramatsu 		c = nc;
15752a9c8c36SMasami Hiramatsu 		if (c == ';') {	/* Lazy pattern must be the last part */
1576c588d158SMasami Hiramatsu 			pp->lazy_line = strdup(arg); /* let leave escapes */
157702b95dadSMasami Hiramatsu 			if (pp->lazy_line == NULL)
157802b95dadSMasami Hiramatsu 				return -ENOMEM;
15792a9c8c36SMasami Hiramatsu 			break;
15802a9c8c36SMasami Hiramatsu 		}
1581c588d158SMasami Hiramatsu 		ptr = strpbrk_esc(arg, ";:+@%");
158250656eecSMasami Hiramatsu 		if (ptr) {
158350656eecSMasami Hiramatsu 			nc = *ptr;
158450656eecSMasami Hiramatsu 			*ptr++ = '\0';
158550656eecSMasami Hiramatsu 		}
158650656eecSMasami Hiramatsu 		switch (c) {
158750656eecSMasami Hiramatsu 		case ':':	/* Line number */
158850656eecSMasami Hiramatsu 			pp->line = strtoul(arg, &tmp, 0);
1589146a1439SMasami Hiramatsu 			if (*tmp != '\0') {
15902a9c8c36SMasami Hiramatsu 				semantic_error("There is non-digit char"
1591146a1439SMasami Hiramatsu 					       " in line number.\n");
1592146a1439SMasami Hiramatsu 				return -EINVAL;
1593146a1439SMasami Hiramatsu 			}
159450656eecSMasami Hiramatsu 			break;
159550656eecSMasami Hiramatsu 		case '+':	/* Byte offset from a symbol */
159650656eecSMasami Hiramatsu 			pp->offset = strtoul(arg, &tmp, 0);
1597146a1439SMasami Hiramatsu 			if (*tmp != '\0') {
15982a9c8c36SMasami Hiramatsu 				semantic_error("There is non-digit character"
1599146a1439SMasami Hiramatsu 						" in offset.\n");
1600146a1439SMasami Hiramatsu 				return -EINVAL;
1601146a1439SMasami Hiramatsu 			}
160250656eecSMasami Hiramatsu 			break;
160350656eecSMasami Hiramatsu 		case '@':	/* File name */
1604146a1439SMasami Hiramatsu 			if (pp->file) {
1605146a1439SMasami Hiramatsu 				semantic_error("SRC@SRC is not allowed.\n");
1606146a1439SMasami Hiramatsu 				return -EINVAL;
1607146a1439SMasami Hiramatsu 			}
1608c588d158SMasami Hiramatsu 			pp->file = strdup_esc(arg);
160902b95dadSMasami Hiramatsu 			if (pp->file == NULL)
161002b95dadSMasami Hiramatsu 				return -ENOMEM;
161150656eecSMasami Hiramatsu 			break;
161250656eecSMasami Hiramatsu 		case '%':	/* Probe places */
161350656eecSMasami Hiramatsu 			if (strcmp(arg, "return") == 0) {
161450656eecSMasami Hiramatsu 				pp->retprobe = 1;
1615146a1439SMasami Hiramatsu 			} else {	/* Others not supported yet */
1616146a1439SMasami Hiramatsu 				semantic_error("%%%s is not supported.\n", arg);
1617146a1439SMasami Hiramatsu 				return -ENOTSUP;
1618146a1439SMasami Hiramatsu 			}
161950656eecSMasami Hiramatsu 			break;
1620146a1439SMasami Hiramatsu 		default:	/* Buggy case */
1621146a1439SMasami Hiramatsu 			pr_err("This program has a bug at %s:%d.\n",
1622146a1439SMasami Hiramatsu 				__FILE__, __LINE__);
1623146a1439SMasami Hiramatsu 			return -ENOTSUP;
162450656eecSMasami Hiramatsu 			break;
162550656eecSMasami Hiramatsu 		}
162650656eecSMasami Hiramatsu 	}
162750656eecSMasami Hiramatsu 
162850656eecSMasami Hiramatsu 	/* Exclusion check */
1629146a1439SMasami Hiramatsu 	if (pp->lazy_line && pp->line) {
16300e43e5d2SMasami Hiramatsu 		semantic_error("Lazy pattern can't be used with"
16310e43e5d2SMasami Hiramatsu 			       " line number.\n");
1632146a1439SMasami Hiramatsu 		return -EINVAL;
1633146a1439SMasami Hiramatsu 	}
16342a9c8c36SMasami Hiramatsu 
1635146a1439SMasami Hiramatsu 	if (pp->lazy_line && pp->offset) {
16360e43e5d2SMasami Hiramatsu 		semantic_error("Lazy pattern can't be used with offset.\n");
1637146a1439SMasami Hiramatsu 		return -EINVAL;
1638146a1439SMasami Hiramatsu 	}
16392a9c8c36SMasami Hiramatsu 
1640146a1439SMasami Hiramatsu 	if (pp->line && pp->offset) {
16410e43e5d2SMasami Hiramatsu 		semantic_error("Offset can't be used with line number.\n");
1642146a1439SMasami Hiramatsu 		return -EINVAL;
1643146a1439SMasami Hiramatsu 	}
164450656eecSMasami Hiramatsu 
1645146a1439SMasami Hiramatsu 	if (!pp->line && !pp->lazy_line && pp->file && !pp->function) {
16462a9c8c36SMasami Hiramatsu 		semantic_error("File always requires line number or "
16470e43e5d2SMasami Hiramatsu 			       "lazy pattern.\n");
1648146a1439SMasami Hiramatsu 		return -EINVAL;
1649146a1439SMasami Hiramatsu 	}
165050656eecSMasami Hiramatsu 
1651146a1439SMasami Hiramatsu 	if (pp->offset && !pp->function) {
16520e43e5d2SMasami Hiramatsu 		semantic_error("Offset requires an entry function.\n");
1653146a1439SMasami Hiramatsu 		return -EINVAL;
1654146a1439SMasami Hiramatsu 	}
165550656eecSMasami Hiramatsu 
1656146a1439SMasami Hiramatsu 	if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
16572a9c8c36SMasami Hiramatsu 		semantic_error("Offset/Line/Lazy pattern can't be used with "
16580e43e5d2SMasami Hiramatsu 			       "return probe.\n");
1659146a1439SMasami Hiramatsu 		return -EINVAL;
1660146a1439SMasami Hiramatsu 	}
166150656eecSMasami Hiramatsu 
16624235b045SMasami Hiramatsu 	pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
16632a9c8c36SMasami Hiramatsu 		 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
16642a9c8c36SMasami Hiramatsu 		 pp->lazy_line);
1665146a1439SMasami Hiramatsu 	return 0;
166650656eecSMasami Hiramatsu }
166750656eecSMasami Hiramatsu 
16687df2f329SMasami Hiramatsu /* Parse perf-probe event argument */
1669146a1439SMasami Hiramatsu static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
16707df2f329SMasami Hiramatsu {
1671b2a3c12bSMasami Hiramatsu 	char *tmp, *goodname;
16727df2f329SMasami Hiramatsu 	struct perf_probe_arg_field **fieldp;
16737df2f329SMasami Hiramatsu 
16747df2f329SMasami Hiramatsu 	pr_debug("parsing arg: %s into ", str);
16757df2f329SMasami Hiramatsu 
167648481938SMasami Hiramatsu 	tmp = strchr(str, '=');
167748481938SMasami Hiramatsu 	if (tmp) {
167802b95dadSMasami Hiramatsu 		arg->name = strndup(str, tmp - str);
167902b95dadSMasami Hiramatsu 		if (arg->name == NULL)
168002b95dadSMasami Hiramatsu 			return -ENOMEM;
168111a1ca35SMasami Hiramatsu 		pr_debug("name:%s ", arg->name);
168248481938SMasami Hiramatsu 		str = tmp + 1;
168348481938SMasami Hiramatsu 	}
168448481938SMasami Hiramatsu 
16851e032f7cSMasami Hiramatsu 	tmp = strchr(str, '@');
16869256c303SSumanth Korikkar 	if (tmp && tmp != str && !strcmp(tmp + 1, "user")) { /* user attr */
16871e032f7cSMasami Hiramatsu 		if (!user_access_is_supported()) {
16881e032f7cSMasami Hiramatsu 			semantic_error("ftrace does not support user access\n");
16891e032f7cSMasami Hiramatsu 			return -EINVAL;
16901e032f7cSMasami Hiramatsu 		}
16911e032f7cSMasami Hiramatsu 		*tmp = '\0';
16921e032f7cSMasami Hiramatsu 		arg->user_access = true;
16931e032f7cSMasami Hiramatsu 		pr_debug("user_access ");
16941e032f7cSMasami Hiramatsu 	}
16951e032f7cSMasami Hiramatsu 
169611a1ca35SMasami Hiramatsu 	tmp = strchr(str, ':');
169711a1ca35SMasami Hiramatsu 	if (tmp) {	/* Type setting */
169811a1ca35SMasami Hiramatsu 		*tmp = '\0';
169902b95dadSMasami Hiramatsu 		arg->type = strdup(tmp + 1);
170002b95dadSMasami Hiramatsu 		if (arg->type == NULL)
170102b95dadSMasami Hiramatsu 			return -ENOMEM;
170211a1ca35SMasami Hiramatsu 		pr_debug("type:%s ", arg->type);
170311a1ca35SMasami Hiramatsu 	}
170411a1ca35SMasami Hiramatsu 
1705b2a3c12bSMasami Hiramatsu 	tmp = strpbrk(str, "-.[");
17067df2f329SMasami Hiramatsu 	if (!is_c_varname(str) || !tmp) {
17077df2f329SMasami Hiramatsu 		/* A variable, register, symbol or special value */
170802b95dadSMasami Hiramatsu 		arg->var = strdup(str);
170902b95dadSMasami Hiramatsu 		if (arg->var == NULL)
171002b95dadSMasami Hiramatsu 			return -ENOMEM;
171148481938SMasami Hiramatsu 		pr_debug("%s\n", arg->var);
1712146a1439SMasami Hiramatsu 		return 0;
17137df2f329SMasami Hiramatsu 	}
17147df2f329SMasami Hiramatsu 
1715b2a3c12bSMasami Hiramatsu 	/* Structure fields or array element */
171602b95dadSMasami Hiramatsu 	arg->var = strndup(str, tmp - str);
171702b95dadSMasami Hiramatsu 	if (arg->var == NULL)
171802b95dadSMasami Hiramatsu 		return -ENOMEM;
1719b2a3c12bSMasami Hiramatsu 	goodname = arg->var;
172048481938SMasami Hiramatsu 	pr_debug("%s, ", arg->var);
17217df2f329SMasami Hiramatsu 	fieldp = &arg->field;
17227df2f329SMasami Hiramatsu 
17237df2f329SMasami Hiramatsu 	do {
1724e334016fSMasami Hiramatsu 		*fieldp = zalloc(sizeof(struct perf_probe_arg_field));
1725e334016fSMasami Hiramatsu 		if (*fieldp == NULL)
1726e334016fSMasami Hiramatsu 			return -ENOMEM;
1727b2a3c12bSMasami Hiramatsu 		if (*tmp == '[') {	/* Array */
1728b2a3c12bSMasami Hiramatsu 			str = tmp;
1729b2a3c12bSMasami Hiramatsu 			(*fieldp)->index = strtol(str + 1, &tmp, 0);
1730b2a3c12bSMasami Hiramatsu 			(*fieldp)->ref = true;
1731b2a3c12bSMasami Hiramatsu 			if (*tmp != ']' || tmp == str + 1) {
1732b2a3c12bSMasami Hiramatsu 				semantic_error("Array index must be a"
1733b2a3c12bSMasami Hiramatsu 						" number.\n");
1734b2a3c12bSMasami Hiramatsu 				return -EINVAL;
1735b2a3c12bSMasami Hiramatsu 			}
1736b2a3c12bSMasami Hiramatsu 			tmp++;
1737b2a3c12bSMasami Hiramatsu 			if (*tmp == '\0')
1738b2a3c12bSMasami Hiramatsu 				tmp = NULL;
1739b2a3c12bSMasami Hiramatsu 		} else {		/* Structure */
17407df2f329SMasami Hiramatsu 			if (*tmp == '.') {
17417df2f329SMasami Hiramatsu 				str = tmp + 1;
17427df2f329SMasami Hiramatsu 				(*fieldp)->ref = false;
17437df2f329SMasami Hiramatsu 			} else if (tmp[1] == '>') {
17447df2f329SMasami Hiramatsu 				str = tmp + 2;
17457df2f329SMasami Hiramatsu 				(*fieldp)->ref = true;
1746146a1439SMasami Hiramatsu 			} else {
1747b2a3c12bSMasami Hiramatsu 				semantic_error("Argument parse error: %s\n",
1748b2a3c12bSMasami Hiramatsu 					       str);
1749146a1439SMasami Hiramatsu 				return -EINVAL;
1750146a1439SMasami Hiramatsu 			}
1751b2a3c12bSMasami Hiramatsu 			tmp = strpbrk(str, "-.[");
1752b2a3c12bSMasami Hiramatsu 		}
17537df2f329SMasami Hiramatsu 		if (tmp) {
175402b95dadSMasami Hiramatsu 			(*fieldp)->name = strndup(str, tmp - str);
175502b95dadSMasami Hiramatsu 			if ((*fieldp)->name == NULL)
175602b95dadSMasami Hiramatsu 				return -ENOMEM;
1757b2a3c12bSMasami Hiramatsu 			if (*str != '[')
1758b2a3c12bSMasami Hiramatsu 				goodname = (*fieldp)->name;
17597df2f329SMasami Hiramatsu 			pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
17607df2f329SMasami Hiramatsu 			fieldp = &(*fieldp)->next;
17617df2f329SMasami Hiramatsu 		}
17627df2f329SMasami Hiramatsu 	} while (tmp);
176302b95dadSMasami Hiramatsu 	(*fieldp)->name = strdup(str);
176402b95dadSMasami Hiramatsu 	if ((*fieldp)->name == NULL)
176502b95dadSMasami Hiramatsu 		return -ENOMEM;
1766b2a3c12bSMasami Hiramatsu 	if (*str != '[')
1767b2a3c12bSMasami Hiramatsu 		goodname = (*fieldp)->name;
17687df2f329SMasami Hiramatsu 	pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
1769df0faf4bSMasami Hiramatsu 
1770b2a3c12bSMasami Hiramatsu 	/* If no name is specified, set the last field name (not array index)*/
177102b95dadSMasami Hiramatsu 	if (!arg->name) {
1772b2a3c12bSMasami Hiramatsu 		arg->name = strdup(goodname);
177302b95dadSMasami Hiramatsu 		if (arg->name == NULL)
177402b95dadSMasami Hiramatsu 			return -ENOMEM;
177502b95dadSMasami Hiramatsu 	}
1776146a1439SMasami Hiramatsu 	return 0;
17777df2f329SMasami Hiramatsu }
17787df2f329SMasami Hiramatsu 
17794235b045SMasami Hiramatsu /* Parse perf-probe event command */
1780146a1439SMasami Hiramatsu int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
178150656eecSMasami Hiramatsu {
1782e1c01d61SMasami Hiramatsu 	char **argv;
1783146a1439SMasami Hiramatsu 	int argc, i, ret = 0;
1784fac13fd5SMasami Hiramatsu 
17854235b045SMasami Hiramatsu 	argv = argv_split(cmd, &argc);
1786146a1439SMasami Hiramatsu 	if (!argv) {
1787146a1439SMasami Hiramatsu 		pr_debug("Failed to split arguments.\n");
1788146a1439SMasami Hiramatsu 		return -ENOMEM;
1789146a1439SMasami Hiramatsu 	}
1790146a1439SMasami Hiramatsu 	if (argc - 1 > MAX_PROBE_ARGS) {
1791146a1439SMasami Hiramatsu 		semantic_error("Too many probe arguments (%d).\n", argc - 1);
1792146a1439SMasami Hiramatsu 		ret = -ERANGE;
1793146a1439SMasami Hiramatsu 		goto out;
1794146a1439SMasami Hiramatsu 	}
179550656eecSMasami Hiramatsu 	/* Parse probe point */
1796146a1439SMasami Hiramatsu 	ret = parse_perf_probe_point(argv[0], pev);
1797146a1439SMasami Hiramatsu 	if (ret < 0)
1798146a1439SMasami Hiramatsu 		goto out;
179950656eecSMasami Hiramatsu 
180015354d54SMasami Hiramatsu 	/* Generate event name if needed */
180115354d54SMasami Hiramatsu 	if (!pev->event && pev->point.function && pev->point.line
180215354d54SMasami Hiramatsu 			&& !pev->point.lazy_line && !pev->point.offset) {
180315354d54SMasami Hiramatsu 		if (asprintf(&pev->event, "%s_L%d", pev->point.function,
18044bf6dcaaSChristophe JAILLET 			pev->point.line) < 0) {
18054bf6dcaaSChristophe JAILLET 			ret = -ENOMEM;
18064bf6dcaaSChristophe JAILLET 			goto out;
18074bf6dcaaSChristophe JAILLET 		}
180815354d54SMasami Hiramatsu 	}
180915354d54SMasami Hiramatsu 
1810e1c01d61SMasami Hiramatsu 	/* Copy arguments and ensure return probe has no C argument */
18114235b045SMasami Hiramatsu 	pev->nargs = argc - 1;
1812e334016fSMasami Hiramatsu 	pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
1813e334016fSMasami Hiramatsu 	if (pev->args == NULL) {
1814e334016fSMasami Hiramatsu 		ret = -ENOMEM;
1815e334016fSMasami Hiramatsu 		goto out;
1816e334016fSMasami Hiramatsu 	}
1817146a1439SMasami Hiramatsu 	for (i = 0; i < pev->nargs && ret >= 0; i++) {
1818146a1439SMasami Hiramatsu 		ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]);
1819146a1439SMasami Hiramatsu 		if (ret >= 0 &&
1820146a1439SMasami Hiramatsu 		    is_c_varname(pev->args[i].var) && pev->point.retprobe) {
18214235b045SMasami Hiramatsu 			semantic_error("You can't specify local variable for"
1822146a1439SMasami Hiramatsu 				       " kretprobe.\n");
1823146a1439SMasami Hiramatsu 			ret = -EINVAL;
1824e1c01d61SMasami Hiramatsu 		}
1825146a1439SMasami Hiramatsu 	}
1826146a1439SMasami Hiramatsu out:
1827e1c01d61SMasami Hiramatsu 	argv_free(argv);
1828146a1439SMasami Hiramatsu 
1829146a1439SMasami Hiramatsu 	return ret;
183050656eecSMasami Hiramatsu }
183150656eecSMasami Hiramatsu 
1832b3f33f93SRavi Bangoria /* Returns true if *any* ARG is either C variable, $params or $vars. */
1833b3f33f93SRavi Bangoria bool perf_probe_with_var(struct perf_probe_event *pev)
18344de189feSMasami Hiramatsu {
1835b3f33f93SRavi Bangoria 	int i = 0;
18364235b045SMasami Hiramatsu 
18374235b045SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++)
1838f6eb0518SMasami Hiramatsu 		if (is_c_varname(pev->args[i].var)              ||
1839b3f33f93SRavi Bangoria 		    !strcmp(pev->args[i].var, PROBE_ARG_PARAMS) ||
1840b3f33f93SRavi Bangoria 		    !strcmp(pev->args[i].var, PROBE_ARG_VARS))
1841b3f33f93SRavi Bangoria 			return true;
1842b3f33f93SRavi Bangoria 	return false;
1843b3f33f93SRavi Bangoria }
1844b3f33f93SRavi Bangoria 
1845b3f33f93SRavi Bangoria /* Return true if this perf_probe_event requires debuginfo */
1846b3f33f93SRavi Bangoria bool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
1847b3f33f93SRavi Bangoria {
1848b3f33f93SRavi Bangoria 	if (pev->point.file || pev->point.line || pev->point.lazy_line)
1849b3f33f93SRavi Bangoria 		return true;
1850b3f33f93SRavi Bangoria 
1851b3f33f93SRavi Bangoria 	if (perf_probe_with_var(pev))
18524235b045SMasami Hiramatsu 		return true;
18534235b045SMasami Hiramatsu 
18544235b045SMasami Hiramatsu 	return false;
18554235b045SMasami Hiramatsu }
18564235b045SMasami Hiramatsu 
18570e60836bSSrikar Dronamraju /* Parse probe_events event into struct probe_point */
185892f6c72eSMasami Hiramatsu int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev)
18594235b045SMasami Hiramatsu {
18600e60836bSSrikar Dronamraju 	struct probe_trace_point *tp = &tev->point;
18614de189feSMasami Hiramatsu 	char pr;
18624de189feSMasami Hiramatsu 	char *p;
1863bcbd0040SIrina Tirdea 	char *argv0_str = NULL, *fmt, *fmt1_str, *fmt2_str, *fmt3_str;
18644de189feSMasami Hiramatsu 	int ret, i, argc;
18654de189feSMasami Hiramatsu 	char **argv;
18664de189feSMasami Hiramatsu 
18670e60836bSSrikar Dronamraju 	pr_debug("Parsing probe_events: %s\n", cmd);
18684235b045SMasami Hiramatsu 	argv = argv_split(cmd, &argc);
1869146a1439SMasami Hiramatsu 	if (!argv) {
1870146a1439SMasami Hiramatsu 		pr_debug("Failed to split arguments.\n");
1871146a1439SMasami Hiramatsu 		return -ENOMEM;
1872146a1439SMasami Hiramatsu 	}
1873146a1439SMasami Hiramatsu 	if (argc < 2) {
1874146a1439SMasami Hiramatsu 		semantic_error("Too few probe arguments.\n");
1875146a1439SMasami Hiramatsu 		ret = -ERANGE;
1876146a1439SMasami Hiramatsu 		goto out;
1877146a1439SMasami Hiramatsu 	}
18784de189feSMasami Hiramatsu 
18794de189feSMasami Hiramatsu 	/* Scan event and group name. */
1880bcbd0040SIrina Tirdea 	argv0_str = strdup(argv[0]);
1881bcbd0040SIrina Tirdea 	if (argv0_str == NULL) {
1882bcbd0040SIrina Tirdea 		ret = -ENOMEM;
1883bcbd0040SIrina Tirdea 		goto out;
1884bcbd0040SIrina Tirdea 	}
1885bcbd0040SIrina Tirdea 	fmt1_str = strtok_r(argv0_str, ":", &fmt);
1886bcbd0040SIrina Tirdea 	fmt2_str = strtok_r(NULL, "/", &fmt);
1887bcbd0040SIrina Tirdea 	fmt3_str = strtok_r(NULL, " \t", &fmt);
1888c6aab66aSMasami Hiramatsu 	if (fmt1_str == NULL || fmt2_str == NULL || fmt3_str == NULL) {
1889146a1439SMasami Hiramatsu 		semantic_error("Failed to parse event name: %s\n", argv[0]);
1890146a1439SMasami Hiramatsu 		ret = -EINVAL;
1891146a1439SMasami Hiramatsu 		goto out;
1892146a1439SMasami Hiramatsu 	}
1893bcbd0040SIrina Tirdea 	pr = fmt1_str[0];
1894bcbd0040SIrina Tirdea 	tev->group = strdup(fmt2_str);
1895bcbd0040SIrina Tirdea 	tev->event = strdup(fmt3_str);
1896bcbd0040SIrina Tirdea 	if (tev->group == NULL || tev->event == NULL) {
1897bcbd0040SIrina Tirdea 		ret = -ENOMEM;
1898bcbd0040SIrina Tirdea 		goto out;
1899bcbd0040SIrina Tirdea 	}
19004235b045SMasami Hiramatsu 	pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr);
19014de189feSMasami Hiramatsu 
19024235b045SMasami Hiramatsu 	tp->retprobe = (pr == 'r');
19034de189feSMasami Hiramatsu 
1904190b57fcSMasami Hiramatsu 	/* Scan module name(if there), function name and offset */
1905190b57fcSMasami Hiramatsu 	p = strchr(argv[1], ':');
1906190b57fcSMasami Hiramatsu 	if (p) {
1907190b57fcSMasami Hiramatsu 		tp->module = strndup(argv[1], p - argv[1]);
1908844faa4bSMasami Hiramatsu 		if (!tp->module) {
1909844faa4bSMasami Hiramatsu 			ret = -ENOMEM;
1910844faa4bSMasami Hiramatsu 			goto out;
1911844faa4bSMasami Hiramatsu 		}
191242bba263SMasami Hiramatsu 		tev->uprobes = (tp->module[0] == '/');
1913190b57fcSMasami Hiramatsu 		p++;
1914190b57fcSMasami Hiramatsu 	} else
1915190b57fcSMasami Hiramatsu 		p = argv[1];
1916bcbd0040SIrina Tirdea 	fmt1_str = strtok_r(p, "+", &fmt);
1917be07afe9SWang Nan 	/* only the address started with 0x */
1918be07afe9SWang Nan 	if (fmt1_str[0] == '0')	{
1919be07afe9SWang Nan 		/*
1920be07afe9SWang Nan 		 * Fix a special case:
1921be07afe9SWang Nan 		 * if address == 0, kernel reports something like:
1922be07afe9SWang Nan 		 * p:probe_libc/abs_0 /lib/libc-2.18.so:0x          (null) arg1=%ax
1923be07afe9SWang Nan 		 * Newer kernel may fix that, but we want to
1924be07afe9SWang Nan 		 * support old kernel also.
1925be07afe9SWang Nan 		 */
1926be07afe9SWang Nan 		if (strcmp(fmt1_str, "0x") == 0) {
1927be07afe9SWang Nan 			if (!argv[2] || strcmp(argv[2], "(null)")) {
1928be07afe9SWang Nan 				ret = -EINVAL;
1929be07afe9SWang Nan 				goto out;
1930be07afe9SWang Nan 			}
1931be07afe9SWang Nan 			tp->address = 0;
1932be07afe9SWang Nan 
1933be07afe9SWang Nan 			free(argv[2]);
1934be07afe9SWang Nan 			for (i = 2; argv[i + 1] != NULL; i++)
1935be07afe9SWang Nan 				argv[i] = argv[i + 1];
1936be07afe9SWang Nan 
1937be07afe9SWang Nan 			argv[i] = NULL;
1938be07afe9SWang Nan 			argc -= 1;
1939be07afe9SWang Nan 		} else
194022a66551SYang Jihong 			tp->address = strtoull(fmt1_str, NULL, 0);
1941be07afe9SWang Nan 	} else {
19425a6f6314SMasami Hiramatsu 		/* Only the symbol-based probe has offset */
1943bcbd0040SIrina Tirdea 		tp->symbol = strdup(fmt1_str);
1944bcbd0040SIrina Tirdea 		if (tp->symbol == NULL) {
1945bcbd0040SIrina Tirdea 			ret = -ENOMEM;
1946bcbd0040SIrina Tirdea 			goto out;
1947bcbd0040SIrina Tirdea 		}
1948bcbd0040SIrina Tirdea 		fmt2_str = strtok_r(NULL, "", &fmt);
1949bcbd0040SIrina Tirdea 		if (fmt2_str == NULL)
19504235b045SMasami Hiramatsu 			tp->offset = 0;
1951bcbd0040SIrina Tirdea 		else
1952bcbd0040SIrina Tirdea 			tp->offset = strtoul(fmt2_str, NULL, 10);
19535a6f6314SMasami Hiramatsu 	}
19544de189feSMasami Hiramatsu 
19555a5e3d3cSRavi Bangoria 	if (tev->uprobes) {
19565a5e3d3cSRavi Bangoria 		fmt2_str = strchr(p, '(');
19575a5e3d3cSRavi Bangoria 		if (fmt2_str)
19585a5e3d3cSRavi Bangoria 			tp->ref_ctr_offset = strtoul(fmt2_str + 1, NULL, 0);
19595a5e3d3cSRavi Bangoria 	}
19605a5e3d3cSRavi Bangoria 
19614235b045SMasami Hiramatsu 	tev->nargs = argc - 2;
19620e60836bSSrikar Dronamraju 	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
1963e334016fSMasami Hiramatsu 	if (tev->args == NULL) {
1964e334016fSMasami Hiramatsu 		ret = -ENOMEM;
1965e334016fSMasami Hiramatsu 		goto out;
1966e334016fSMasami Hiramatsu 	}
19674235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
19684de189feSMasami Hiramatsu 		p = strchr(argv[i + 2], '=');
19694de189feSMasami Hiramatsu 		if (p)	/* We don't need which register is assigned. */
19704235b045SMasami Hiramatsu 			*p++ = '\0';
19714235b045SMasami Hiramatsu 		else
19724235b045SMasami Hiramatsu 			p = argv[i + 2];
197302b95dadSMasami Hiramatsu 		tev->args[i].name = strdup(argv[i + 2]);
19744235b045SMasami Hiramatsu 		/* TODO: parse regs and offset */
197502b95dadSMasami Hiramatsu 		tev->args[i].value = strdup(p);
197602b95dadSMasami Hiramatsu 		if (tev->args[i].name == NULL || tev->args[i].value == NULL) {
197702b95dadSMasami Hiramatsu 			ret = -ENOMEM;
197802b95dadSMasami Hiramatsu 			goto out;
197902b95dadSMasami Hiramatsu 		}
19804de189feSMasami Hiramatsu 	}
1981146a1439SMasami Hiramatsu 	ret = 0;
1982146a1439SMasami Hiramatsu out:
1983bcbd0040SIrina Tirdea 	free(argv0_str);
19844de189feSMasami Hiramatsu 	argv_free(argv);
1985146a1439SMasami Hiramatsu 	return ret;
19864de189feSMasami Hiramatsu }
19874de189feSMasami Hiramatsu 
19887df2f329SMasami Hiramatsu /* Compose only probe arg */
1989909b0360SMasami Hiramatsu char *synthesize_perf_probe_arg(struct perf_probe_arg *pa)
19907df2f329SMasami Hiramatsu {
19917df2f329SMasami Hiramatsu 	struct perf_probe_arg_field *field = pa->field;
1992909b0360SMasami Hiramatsu 	struct strbuf buf;
1993bf4d5f25SMasami Hiramatsu 	char *ret = NULL;
1994bf4d5f25SMasami Hiramatsu 	int err;
19957df2f329SMasami Hiramatsu 
1996bf4d5f25SMasami Hiramatsu 	if (strbuf_init(&buf, 64) < 0)
1997bf4d5f25SMasami Hiramatsu 		return NULL;
1998bf4d5f25SMasami Hiramatsu 
199948481938SMasami Hiramatsu 	if (pa->name && pa->var)
2000bf4d5f25SMasami Hiramatsu 		err = strbuf_addf(&buf, "%s=%s", pa->name, pa->var);
200148481938SMasami Hiramatsu 	else
2002bf4d5f25SMasami Hiramatsu 		err = strbuf_addstr(&buf, pa->name ?: pa->var);
2003bf4d5f25SMasami Hiramatsu 	if (err)
2004bf4d5f25SMasami Hiramatsu 		goto out;
20057df2f329SMasami Hiramatsu 
20067df2f329SMasami Hiramatsu 	while (field) {
2007b2a3c12bSMasami Hiramatsu 		if (field->name[0] == '[')
2008bf4d5f25SMasami Hiramatsu 			err = strbuf_addstr(&buf, field->name);
2009b2a3c12bSMasami Hiramatsu 		else
2010bf4d5f25SMasami Hiramatsu 			err = strbuf_addf(&buf, "%s%s", field->ref ? "->" : ".",
2011909b0360SMasami Hiramatsu 					  field->name);
20127df2f329SMasami Hiramatsu 		field = field->next;
2013bf4d5f25SMasami Hiramatsu 		if (err)
2014bf4d5f25SMasami Hiramatsu 			goto out;
20157df2f329SMasami Hiramatsu 	}
201611a1ca35SMasami Hiramatsu 
2017909b0360SMasami Hiramatsu 	if (pa->type)
2018bf4d5f25SMasami Hiramatsu 		if (strbuf_addf(&buf, ":%s", pa->type) < 0)
2019bf4d5f25SMasami Hiramatsu 			goto out;
202011a1ca35SMasami Hiramatsu 
2021909b0360SMasami Hiramatsu 	ret = strbuf_detach(&buf, NULL);
2022bf4d5f25SMasami Hiramatsu out:
2023bf4d5f25SMasami Hiramatsu 	strbuf_release(&buf);
2024146a1439SMasami Hiramatsu 	return ret;
20257df2f329SMasami Hiramatsu }
20267df2f329SMasami Hiramatsu 
20274235b045SMasami Hiramatsu /* Compose only probe point (not argument) */
2028aeb50d3fSArnaldo Carvalho de Melo static char *synthesize_perf_probe_point(struct perf_probe_point *pp)
202950656eecSMasami Hiramatsu {
2030909b0360SMasami Hiramatsu 	struct strbuf buf;
2031bf4d5f25SMasami Hiramatsu 	char *tmp, *ret = NULL;
2032bf4d5f25SMasami Hiramatsu 	int len, err = 0;
203350656eecSMasami Hiramatsu 
2034bf4d5f25SMasami Hiramatsu 	if (strbuf_init(&buf, 64) < 0)
2035bf4d5f25SMasami Hiramatsu 		return NULL;
2036bf4d5f25SMasami Hiramatsu 
2037909b0360SMasami Hiramatsu 	if (pp->function) {
2038bf4d5f25SMasami Hiramatsu 		if (strbuf_addstr(&buf, pp->function) < 0)
2039bf4d5f25SMasami Hiramatsu 			goto out;
2040909b0360SMasami Hiramatsu 		if (pp->offset)
2041bf4d5f25SMasami Hiramatsu 			err = strbuf_addf(&buf, "+%lu", pp->offset);
2042909b0360SMasami Hiramatsu 		else if (pp->line)
2043bf4d5f25SMasami Hiramatsu 			err = strbuf_addf(&buf, ":%d", pp->line);
2044909b0360SMasami Hiramatsu 		else if (pp->retprobe)
2045bf4d5f25SMasami Hiramatsu 			err = strbuf_addstr(&buf, "%return");
2046bf4d5f25SMasami Hiramatsu 		if (err)
2047bf4d5f25SMasami Hiramatsu 			goto out;
2048fb1587d8SMasami Hiramatsu 	}
2049fb1587d8SMasami Hiramatsu 	if (pp->file) {
205032ae2adeSFranck Bui-Huu 		tmp = pp->file;
205132ae2adeSFranck Bui-Huu 		len = strlen(tmp);
205232ae2adeSFranck Bui-Huu 		if (len > 30) {
205332ae2adeSFranck Bui-Huu 			tmp = strchr(pp->file + len - 30, '/');
205432ae2adeSFranck Bui-Huu 			tmp = tmp ? tmp + 1 : pp->file + len - 30;
205532ae2adeSFranck Bui-Huu 		}
2056bf4d5f25SMasami Hiramatsu 		err = strbuf_addf(&buf, "@%s", tmp);
2057bf4d5f25SMasami Hiramatsu 		if (!err && !pp->function && pp->line)
2058bf4d5f25SMasami Hiramatsu 			err = strbuf_addf(&buf, ":%d", pp->line);
20594de189feSMasami Hiramatsu 	}
2060bf4d5f25SMasami Hiramatsu 	if (!err)
2061bf4d5f25SMasami Hiramatsu 		ret = strbuf_detach(&buf, NULL);
2062bf4d5f25SMasami Hiramatsu out:
2063bf4d5f25SMasami Hiramatsu 	strbuf_release(&buf);
2064bf4d5f25SMasami Hiramatsu 	return ret;
20654235b045SMasami Hiramatsu }
20664235b045SMasami Hiramatsu 
20674235b045SMasami Hiramatsu char *synthesize_perf_probe_command(struct perf_probe_event *pev)
20684235b045SMasami Hiramatsu {
2069c4ff4920SMasami Hiramatsu 	struct strbuf buf;
2070c4ff4920SMasami Hiramatsu 	char *tmp, *ret = NULL;
2071c4ff4920SMasami Hiramatsu 	int i;
20724235b045SMasami Hiramatsu 
2073c4ff4920SMasami Hiramatsu 	if (strbuf_init(&buf, 64))
20744235b045SMasami Hiramatsu 		return NULL;
2075c4ff4920SMasami Hiramatsu 	if (pev->event)
2076c4ff4920SMasami Hiramatsu 		if (strbuf_addf(&buf, "%s:%s=", pev->group ?: PERFPROBE_GROUP,
2077c4ff4920SMasami Hiramatsu 				pev->event) < 0)
2078c4ff4920SMasami Hiramatsu 			goto out;
20794235b045SMasami Hiramatsu 
2080c4ff4920SMasami Hiramatsu 	tmp = synthesize_perf_probe_point(&pev->point);
2081a612bbf8SArnaldo Carvalho de Melo 	if (!tmp || strbuf_addstr(&buf, tmp) < 0) {
2082a612bbf8SArnaldo Carvalho de Melo 		free(tmp);
2083c4ff4920SMasami Hiramatsu 		goto out;
2084a612bbf8SArnaldo Carvalho de Melo 	}
2085c4ff4920SMasami Hiramatsu 	free(tmp);
2086c4ff4920SMasami Hiramatsu 
20874235b045SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++) {
2088c4ff4920SMasami Hiramatsu 		tmp = synthesize_perf_probe_arg(pev->args + i);
2089a612bbf8SArnaldo Carvalho de Melo 		if (!tmp || strbuf_addf(&buf, " %s", tmp) < 0) {
2090a612bbf8SArnaldo Carvalho de Melo 			free(tmp);
2091c4ff4920SMasami Hiramatsu 			goto out;
2092a612bbf8SArnaldo Carvalho de Melo 		}
2093c4ff4920SMasami Hiramatsu 		free(tmp);
20947ef17aafSMasami Hiramatsu 	}
209550656eecSMasami Hiramatsu 
2096c4ff4920SMasami Hiramatsu 	ret = strbuf_detach(&buf, NULL);
2097c4ff4920SMasami Hiramatsu out:
2098c4ff4920SMasami Hiramatsu 	strbuf_release(&buf);
2099c4ff4920SMasami Hiramatsu 	return ret;
21004235b045SMasami Hiramatsu }
21014235b045SMasami Hiramatsu 
21020e60836bSSrikar Dronamraju static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
2103909b0360SMasami Hiramatsu 					    struct strbuf *buf, int depth)
21047ef17aafSMasami Hiramatsu {
2105bf4d5f25SMasami Hiramatsu 	int err;
21064235b045SMasami Hiramatsu 	if (ref->next) {
21070e60836bSSrikar Dronamraju 		depth = __synthesize_probe_trace_arg_ref(ref->next, buf,
2108909b0360SMasami Hiramatsu 							 depth + 1);
21094235b045SMasami Hiramatsu 		if (depth < 0)
21104235b045SMasami Hiramatsu 			return depth;
21114235b045SMasami Hiramatsu 	}
21129256c303SSumanth Korikkar 	if (ref->user_access)
21139256c303SSumanth Korikkar 		err = strbuf_addf(buf, "%s%ld(", "+u", ref->offset);
21149256c303SSumanth Korikkar 	else
2115bf4d5f25SMasami Hiramatsu 		err = strbuf_addf(buf, "%+ld(", ref->offset);
2116bf4d5f25SMasami Hiramatsu 	return (err < 0) ? err : depth;
2117bf4d5f25SMasami Hiramatsu }
21184235b045SMasami Hiramatsu 
21190e60836bSSrikar Dronamraju static int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
2120909b0360SMasami Hiramatsu 				      struct strbuf *buf)
21214235b045SMasami Hiramatsu {
21220e60836bSSrikar Dronamraju 	struct probe_trace_arg_ref *ref = arg->ref;
2123bf4d5f25SMasami Hiramatsu 	int depth = 0, err;
21244235b045SMasami Hiramatsu 
21254235b045SMasami Hiramatsu 	/* Argument name or separator */
21264235b045SMasami Hiramatsu 	if (arg->name)
2127bf4d5f25SMasami Hiramatsu 		err = strbuf_addf(buf, " %s=", arg->name);
21284235b045SMasami Hiramatsu 	else
2129bf4d5f25SMasami Hiramatsu 		err = strbuf_addch(buf, ' ');
2130bf4d5f25SMasami Hiramatsu 	if (err)
2131bf4d5f25SMasami Hiramatsu 		return err;
21324235b045SMasami Hiramatsu 
2133b7dcb857SMasami Hiramatsu 	/* Special case: @XXX */
2134b7dcb857SMasami Hiramatsu 	if (arg->value[0] == '@' && arg->ref)
2135b7dcb857SMasami Hiramatsu 			ref = ref->next;
2136b7dcb857SMasami Hiramatsu 
21374235b045SMasami Hiramatsu 	/* Dereferencing arguments */
2138b7dcb857SMasami Hiramatsu 	if (ref) {
2139909b0360SMasami Hiramatsu 		depth = __synthesize_probe_trace_arg_ref(ref, buf, 1);
21404235b045SMasami Hiramatsu 		if (depth < 0)
21414235b045SMasami Hiramatsu 			return depth;
21424235b045SMasami Hiramatsu 	}
21434235b045SMasami Hiramatsu 
21444235b045SMasami Hiramatsu 	/* Print argument value */
2145b7dcb857SMasami Hiramatsu 	if (arg->value[0] == '@' && arg->ref)
2146bf4d5f25SMasami Hiramatsu 		err = strbuf_addf(buf, "%s%+ld", arg->value, arg->ref->offset);
2147b7dcb857SMasami Hiramatsu 	else
2148bf4d5f25SMasami Hiramatsu 		err = strbuf_addstr(buf, arg->value);
21494235b045SMasami Hiramatsu 
21504235b045SMasami Hiramatsu 	/* Closing */
2151bf4d5f25SMasami Hiramatsu 	while (!err && depth--)
2152bf4d5f25SMasami Hiramatsu 		err = strbuf_addch(buf, ')');
21534235b045SMasami Hiramatsu 
2154bf4d5f25SMasami Hiramatsu 	/* Print argument type */
2155bf4d5f25SMasami Hiramatsu 	if (!err && arg->type)
2156bf4d5f25SMasami Hiramatsu 		err = strbuf_addf(buf, ":%s", arg->type);
2157bf4d5f25SMasami Hiramatsu 
2158bf4d5f25SMasami Hiramatsu 	return err;
21594235b045SMasami Hiramatsu }
21604235b045SMasami Hiramatsu 
21615a5e3d3cSRavi Bangoria static int
2162d26ea481SMasami Hiramatsu synthesize_probe_trace_args(struct probe_trace_event *tev, struct strbuf *buf)
21635a5e3d3cSRavi Bangoria {
2164d26ea481SMasami Hiramatsu 	int i, ret = 0;
2165d26ea481SMasami Hiramatsu 
2166d26ea481SMasami Hiramatsu 	for (i = 0; i < tev->nargs && ret >= 0; i++)
2167d26ea481SMasami Hiramatsu 		ret = synthesize_probe_trace_arg(&tev->args[i], buf);
2168d26ea481SMasami Hiramatsu 
2169d26ea481SMasami Hiramatsu 	return ret;
2170d26ea481SMasami Hiramatsu }
2171d26ea481SMasami Hiramatsu 
2172d26ea481SMasami Hiramatsu static int
2173d26ea481SMasami Hiramatsu synthesize_uprobe_trace_def(struct probe_trace_point *tp, struct strbuf *buf)
2174d26ea481SMasami Hiramatsu {
21755a5e3d3cSRavi Bangoria 	int err;
21765a5e3d3cSRavi Bangoria 
2177d26ea481SMasami Hiramatsu 	/* Uprobes must have tp->module */
2178d26ea481SMasami Hiramatsu 	if (!tp->module)
2179d26ea481SMasami Hiramatsu 		return -EINVAL;
2180d26ea481SMasami Hiramatsu 	/*
2181d26ea481SMasami Hiramatsu 	 * If tp->address == 0, then this point must be a
2182d26ea481SMasami Hiramatsu 	 * absolute address uprobe.
2183d26ea481SMasami Hiramatsu 	 * try_to_find_absolute_address() should have made
2184d26ea481SMasami Hiramatsu 	 * tp->symbol to "0x0".
2185d26ea481SMasami Hiramatsu 	 */
2186d26ea481SMasami Hiramatsu 	if (!tp->address && (!tp->symbol || strcmp(tp->symbol, "0x0")))
2187d26ea481SMasami Hiramatsu 		return -EINVAL;
2188d26ea481SMasami Hiramatsu 
2189d26ea481SMasami Hiramatsu 	/* Use the tp->address for uprobes */
219022a66551SYang Jihong 	err = strbuf_addf(buf, "%s:0x%" PRIx64, tp->module, tp->address);
21915a5e3d3cSRavi Bangoria 
21925a5e3d3cSRavi Bangoria 	if (err >= 0 && tp->ref_ctr_offset) {
21935a5e3d3cSRavi Bangoria 		if (!uprobe_ref_ctr_is_supported())
2194d26ea481SMasami Hiramatsu 			return -EINVAL;
21955a5e3d3cSRavi Bangoria 		err = strbuf_addf(buf, "(0x%lx)", tp->ref_ctr_offset);
21965a5e3d3cSRavi Bangoria 	}
2197d26ea481SMasami Hiramatsu 	return err >= 0 ? 0 : err;
2198d26ea481SMasami Hiramatsu }
2199d26ea481SMasami Hiramatsu 
2200d26ea481SMasami Hiramatsu static int
2201d26ea481SMasami Hiramatsu synthesize_kprobe_trace_def(struct probe_trace_point *tp, struct strbuf *buf)
2202d26ea481SMasami Hiramatsu {
2203d26ea481SMasami Hiramatsu 	if (!strncmp(tp->symbol, "0x", 2)) {
2204d26ea481SMasami Hiramatsu 		/* Absolute address. See try_to_find_absolute_address() */
220522a66551SYang Jihong 		return strbuf_addf(buf, "%s%s0x%" PRIx64, tp->module ?: "",
2206d26ea481SMasami Hiramatsu 				  tp->module ? ":" : "", tp->address);
2207d26ea481SMasami Hiramatsu 	} else {
2208d26ea481SMasami Hiramatsu 		return strbuf_addf(buf, "%s%s%s+%lu", tp->module ?: "",
2209d26ea481SMasami Hiramatsu 				tp->module ? ":" : "", tp->symbol, tp->offset);
2210d26ea481SMasami Hiramatsu 	}
22115a5e3d3cSRavi Bangoria }
22125a5e3d3cSRavi Bangoria 
22130e60836bSSrikar Dronamraju char *synthesize_probe_trace_command(struct probe_trace_event *tev)
22144235b045SMasami Hiramatsu {
22150e60836bSSrikar Dronamraju 	struct probe_trace_point *tp = &tev->point;
2216909b0360SMasami Hiramatsu 	struct strbuf buf;
2217909b0360SMasami Hiramatsu 	char *ret = NULL;
2218d26ea481SMasami Hiramatsu 	int err;
2219909b0360SMasami Hiramatsu 
2220bf4d5f25SMasami Hiramatsu 	if (strbuf_init(&buf, 32) < 0)
2221bf4d5f25SMasami Hiramatsu 		return NULL;
2222bf4d5f25SMasami Hiramatsu 
2223bf4d5f25SMasami Hiramatsu 	if (strbuf_addf(&buf, "%c:%s/%s ", tp->retprobe ? 'r' : 'p',
2224bf4d5f25SMasami Hiramatsu 			tev->group, tev->event) < 0)
2225bf4d5f25SMasami Hiramatsu 		goto error;
2226eb948e50SMasami Hiramatsu 
2227d26ea481SMasami Hiramatsu 	if (tev->uprobes)
2228d26ea481SMasami Hiramatsu 		err = synthesize_uprobe_trace_def(tp, &buf);
2229d26ea481SMasami Hiramatsu 	else
2230d26ea481SMasami Hiramatsu 		err = synthesize_kprobe_trace_def(tp, &buf);
22315a5e3d3cSRavi Bangoria 
2232d26ea481SMasami Hiramatsu 	if (err >= 0)
2233d26ea481SMasami Hiramatsu 		err = synthesize_probe_trace_args(tev, &buf);
2234225466f1SSrikar Dronamraju 
2235d26ea481SMasami Hiramatsu 	if (err >= 0)
2236909b0360SMasami Hiramatsu 		ret = strbuf_detach(&buf, NULL);
223750656eecSMasami Hiramatsu error:
2238909b0360SMasami Hiramatsu 	strbuf_release(&buf);
2239909b0360SMasami Hiramatsu 	return ret;
224050656eecSMasami Hiramatsu }
224150656eecSMasami Hiramatsu 
22425a6f6314SMasami Hiramatsu static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
22435a6f6314SMasami Hiramatsu 					  struct perf_probe_point *pp,
22445a6f6314SMasami Hiramatsu 					  bool is_kprobe)
22455a6f6314SMasami Hiramatsu {
22465a6f6314SMasami Hiramatsu 	struct symbol *sym = NULL;
22478a2efd6dSArnaldo Carvalho de Melo 	struct map *map = NULL;
2248e486367fSWang Nan 	u64 addr = tp->address;
22495a6f6314SMasami Hiramatsu 	int ret = -ENOENT;
22505a6f6314SMasami Hiramatsu 
22515a6f6314SMasami Hiramatsu 	if (!is_kprobe) {
22525a6f6314SMasami Hiramatsu 		map = dso__new_map(tp->module);
22535a6f6314SMasami Hiramatsu 		if (!map)
22545a6f6314SMasami Hiramatsu 			goto out;
2255be39db9fSArnaldo Carvalho de Melo 		sym = map__find_symbol(map, addr);
22565a6f6314SMasami Hiramatsu 	} else {
22579b239a12SMasami Hiramatsu 		if (tp->symbol && !addr) {
22580a62f686SMasami Hiramatsu 			if (kernel_get_symbol_address_by_name(tp->symbol,
22590a62f686SMasami Hiramatsu 						&addr, true, false) < 0)
22609b239a12SMasami Hiramatsu 				goto out;
22619b239a12SMasami Hiramatsu 		}
22625a6f6314SMasami Hiramatsu 		if (addr) {
22635a6f6314SMasami Hiramatsu 			addr += tp->offset;
2264107cad95SArnaldo Carvalho de Melo 			sym = machine__find_kernel_symbol(host_machine, addr, &map);
22655a6f6314SMasami Hiramatsu 		}
22665a6f6314SMasami Hiramatsu 	}
226798d3b258SWang Nan 
22685a6f6314SMasami Hiramatsu 	if (!sym)
22695a6f6314SMasami Hiramatsu 		goto out;
22705a6f6314SMasami Hiramatsu 
22715a6f6314SMasami Hiramatsu 	pp->retprobe = tp->retprobe;
227278a1f7cdSIan Rogers 	pp->offset = addr - map__unmap_ip(map, sym->start);
22735a6f6314SMasami Hiramatsu 	pp->function = strdup(sym->name);
22745a6f6314SMasami Hiramatsu 	ret = pp->function ? 0 : -ENOMEM;
22755a6f6314SMasami Hiramatsu 
22765a6f6314SMasami Hiramatsu out:
227784c2cafaSArnaldo Carvalho de Melo 	map__put(map);
22785a6f6314SMasami Hiramatsu 
22795a6f6314SMasami Hiramatsu 	return ret;
22805a6f6314SMasami Hiramatsu }
22815a6f6314SMasami Hiramatsu 
22825a6f6314SMasami Hiramatsu static int convert_to_perf_probe_point(struct probe_trace_point *tp,
22835a6f6314SMasami Hiramatsu 				       struct perf_probe_point *pp,
22845a6f6314SMasami Hiramatsu 				       bool is_kprobe)
22855a6f6314SMasami Hiramatsu {
22865a6f6314SMasami Hiramatsu 	char buf[128];
22875a6f6314SMasami Hiramatsu 	int ret;
22885a6f6314SMasami Hiramatsu 
22895a6f6314SMasami Hiramatsu 	ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe);
22905a6f6314SMasami Hiramatsu 	if (!ret)
22915a6f6314SMasami Hiramatsu 		return 0;
22925a6f6314SMasami Hiramatsu 	ret = find_perf_probe_point_from_map(tp, pp, is_kprobe);
22935a6f6314SMasami Hiramatsu 	if (!ret)
22945a6f6314SMasami Hiramatsu 		return 0;
22955a6f6314SMasami Hiramatsu 
22965a6f6314SMasami Hiramatsu 	pr_debug("Failed to find probe point from both of dwarf and map.\n");
22975a6f6314SMasami Hiramatsu 
22985a6f6314SMasami Hiramatsu 	if (tp->symbol) {
22995a6f6314SMasami Hiramatsu 		pp->function = strdup(tp->symbol);
23005a6f6314SMasami Hiramatsu 		pp->offset = tp->offset;
2301614e2fdbSWang Nan 	} else {
230222a66551SYang Jihong 		ret = e_snprintf(buf, 128, "0x%" PRIx64, tp->address);
23035a6f6314SMasami Hiramatsu 		if (ret < 0)
23045a6f6314SMasami Hiramatsu 			return ret;
23055a6f6314SMasami Hiramatsu 		pp->function = strdup(buf);
23065a6f6314SMasami Hiramatsu 		pp->offset = 0;
23075a6f6314SMasami Hiramatsu 	}
23085a6f6314SMasami Hiramatsu 	if (pp->function == NULL)
23095a6f6314SMasami Hiramatsu 		return -ENOMEM;
23105a6f6314SMasami Hiramatsu 
23115a6f6314SMasami Hiramatsu 	pp->retprobe = tp->retprobe;
23125a6f6314SMasami Hiramatsu 
23135a6f6314SMasami Hiramatsu 	return 0;
23145a6f6314SMasami Hiramatsu }
23155a6f6314SMasami Hiramatsu 
23160e60836bSSrikar Dronamraju static int convert_to_perf_probe_event(struct probe_trace_event *tev,
2317225466f1SSrikar Dronamraju 			       struct perf_probe_event *pev, bool is_kprobe)
23184de189feSMasami Hiramatsu {
2319909b0360SMasami Hiramatsu 	struct strbuf buf = STRBUF_INIT;
2320146a1439SMasami Hiramatsu 	int i, ret;
23214de189feSMasami Hiramatsu 
23224b4da7f7SMasami Hiramatsu 	/* Convert event/group name */
232302b95dadSMasami Hiramatsu 	pev->event = strdup(tev->event);
232402b95dadSMasami Hiramatsu 	pev->group = strdup(tev->group);
232502b95dadSMasami Hiramatsu 	if (pev->event == NULL || pev->group == NULL)
232602b95dadSMasami Hiramatsu 		return -ENOMEM;
2327fb1587d8SMasami Hiramatsu 
23284b4da7f7SMasami Hiramatsu 	/* Convert trace_point to probe_point */
23295a6f6314SMasami Hiramatsu 	ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe);
2330146a1439SMasami Hiramatsu 	if (ret < 0)
2331146a1439SMasami Hiramatsu 		return ret;
23324b4da7f7SMasami Hiramatsu 
23334235b045SMasami Hiramatsu 	/* Convert trace_arg to probe_arg */
23344235b045SMasami Hiramatsu 	pev->nargs = tev->nargs;
2335e334016fSMasami Hiramatsu 	pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
2336e334016fSMasami Hiramatsu 	if (pev->args == NULL)
2337e334016fSMasami Hiramatsu 		return -ENOMEM;
233802b95dadSMasami Hiramatsu 	for (i = 0; i < tev->nargs && ret >= 0; i++) {
23394235b045SMasami Hiramatsu 		if (tev->args[i].name)
234002b95dadSMasami Hiramatsu 			pev->args[i].name = strdup(tev->args[i].name);
23414235b045SMasami Hiramatsu 		else {
2342bf4d5f25SMasami Hiramatsu 			if ((ret = strbuf_init(&buf, 32)) < 0)
2343bf4d5f25SMasami Hiramatsu 				goto error;
2344909b0360SMasami Hiramatsu 			ret = synthesize_probe_trace_arg(&tev->args[i], &buf);
2345909b0360SMasami Hiramatsu 			pev->args[i].name = strbuf_detach(&buf, NULL);
234602b95dadSMasami Hiramatsu 		}
234702b95dadSMasami Hiramatsu 		if (pev->args[i].name == NULL && ret >= 0)
234802b95dadSMasami Hiramatsu 			ret = -ENOMEM;
23494de189feSMasami Hiramatsu 	}
2350bf4d5f25SMasami Hiramatsu error:
2351146a1439SMasami Hiramatsu 	if (ret < 0)
2352146a1439SMasami Hiramatsu 		clear_perf_probe_event(pev);
2353146a1439SMasami Hiramatsu 
2354146a1439SMasami Hiramatsu 	return ret;
23554235b045SMasami Hiramatsu }
23564de189feSMasami Hiramatsu 
23574235b045SMasami Hiramatsu void clear_perf_probe_event(struct perf_probe_event *pev)
23584235b045SMasami Hiramatsu {
23597df2f329SMasami Hiramatsu 	struct perf_probe_arg_field *field, *next;
23604235b045SMasami Hiramatsu 	int i;
23614de189feSMasami Hiramatsu 
2362d8f9da24SArnaldo Carvalho de Melo 	zfree(&pev->event);
2363d8f9da24SArnaldo Carvalho de Melo 	zfree(&pev->group);
2364d8f9da24SArnaldo Carvalho de Melo 	zfree(&pev->target);
23659b118acaSMasami Hiramatsu 	clear_perf_probe_point(&pev->point);
2366f5385650SArnaldo Carvalho de Melo 
23677df2f329SMasami Hiramatsu 	for (i = 0; i < pev->nargs; i++) {
2368d8f9da24SArnaldo Carvalho de Melo 		zfree(&pev->args[i].name);
2369d8f9da24SArnaldo Carvalho de Melo 		zfree(&pev->args[i].var);
2370d8f9da24SArnaldo Carvalho de Melo 		zfree(&pev->args[i].type);
23717df2f329SMasami Hiramatsu 		field = pev->args[i].field;
23727df2f329SMasami Hiramatsu 		while (field) {
23737df2f329SMasami Hiramatsu 			next = field->next;
237474cf249dSArnaldo Carvalho de Melo 			zfree(&field->name);
23757df2f329SMasami Hiramatsu 			free(field);
23767df2f329SMasami Hiramatsu 			field = next;
23777df2f329SMasami Hiramatsu 		}
23787df2f329SMasami Hiramatsu 	}
2379df8350edSArnaldo Carvalho de Melo 	pev->nargs = 0;
2380d8f9da24SArnaldo Carvalho de Melo 	zfree(&pev->args);
23814235b045SMasami Hiramatsu }
23824235b045SMasami Hiramatsu 
23830542bb9cSMasami Hiramatsu #define strdup_or_goto(str, label)	\
23840542bb9cSMasami Hiramatsu ({ char *__p = NULL; if (str && !(__p = strdup(str))) goto label; __p; })
23850542bb9cSMasami Hiramatsu 
23860542bb9cSMasami Hiramatsu static int perf_probe_point__copy(struct perf_probe_point *dst,
23870542bb9cSMasami Hiramatsu 				  struct perf_probe_point *src)
23880542bb9cSMasami Hiramatsu {
23890542bb9cSMasami Hiramatsu 	dst->file = strdup_or_goto(src->file, out_err);
23900542bb9cSMasami Hiramatsu 	dst->function = strdup_or_goto(src->function, out_err);
23910542bb9cSMasami Hiramatsu 	dst->lazy_line = strdup_or_goto(src->lazy_line, out_err);
23920542bb9cSMasami Hiramatsu 	dst->line = src->line;
23930542bb9cSMasami Hiramatsu 	dst->retprobe = src->retprobe;
23940542bb9cSMasami Hiramatsu 	dst->offset = src->offset;
23950542bb9cSMasami Hiramatsu 	return 0;
23960542bb9cSMasami Hiramatsu 
23970542bb9cSMasami Hiramatsu out_err:
23980542bb9cSMasami Hiramatsu 	clear_perf_probe_point(dst);
23990542bb9cSMasami Hiramatsu 	return -ENOMEM;
24000542bb9cSMasami Hiramatsu }
24010542bb9cSMasami Hiramatsu 
24020542bb9cSMasami Hiramatsu static int perf_probe_arg__copy(struct perf_probe_arg *dst,
24030542bb9cSMasami Hiramatsu 				struct perf_probe_arg *src)
24040542bb9cSMasami Hiramatsu {
24050542bb9cSMasami Hiramatsu 	struct perf_probe_arg_field *field, **ppfield;
24060542bb9cSMasami Hiramatsu 
24070542bb9cSMasami Hiramatsu 	dst->name = strdup_or_goto(src->name, out_err);
24080542bb9cSMasami Hiramatsu 	dst->var = strdup_or_goto(src->var, out_err);
24090542bb9cSMasami Hiramatsu 	dst->type = strdup_or_goto(src->type, out_err);
24100542bb9cSMasami Hiramatsu 
24110542bb9cSMasami Hiramatsu 	field = src->field;
24120542bb9cSMasami Hiramatsu 	ppfield = &(dst->field);
24130542bb9cSMasami Hiramatsu 	while (field) {
24140542bb9cSMasami Hiramatsu 		*ppfield = zalloc(sizeof(*field));
24150542bb9cSMasami Hiramatsu 		if (!*ppfield)
24160542bb9cSMasami Hiramatsu 			goto out_err;
24170542bb9cSMasami Hiramatsu 		(*ppfield)->name = strdup_or_goto(field->name, out_err);
24180542bb9cSMasami Hiramatsu 		(*ppfield)->index = field->index;
24190542bb9cSMasami Hiramatsu 		(*ppfield)->ref = field->ref;
24200542bb9cSMasami Hiramatsu 		field = field->next;
24210542bb9cSMasami Hiramatsu 		ppfield = &((*ppfield)->next);
24220542bb9cSMasami Hiramatsu 	}
24230542bb9cSMasami Hiramatsu 	return 0;
24240542bb9cSMasami Hiramatsu out_err:
24250542bb9cSMasami Hiramatsu 	return -ENOMEM;
24260542bb9cSMasami Hiramatsu }
24270542bb9cSMasami Hiramatsu 
24280542bb9cSMasami Hiramatsu int perf_probe_event__copy(struct perf_probe_event *dst,
24290542bb9cSMasami Hiramatsu 			   struct perf_probe_event *src)
24300542bb9cSMasami Hiramatsu {
24310542bb9cSMasami Hiramatsu 	int i;
24320542bb9cSMasami Hiramatsu 
24330542bb9cSMasami Hiramatsu 	dst->event = strdup_or_goto(src->event, out_err);
24340542bb9cSMasami Hiramatsu 	dst->group = strdup_or_goto(src->group, out_err);
24350542bb9cSMasami Hiramatsu 	dst->target = strdup_or_goto(src->target, out_err);
24360542bb9cSMasami Hiramatsu 	dst->uprobes = src->uprobes;
24370542bb9cSMasami Hiramatsu 
24380542bb9cSMasami Hiramatsu 	if (perf_probe_point__copy(&dst->point, &src->point) < 0)
24390542bb9cSMasami Hiramatsu 		goto out_err;
24400542bb9cSMasami Hiramatsu 
24410542bb9cSMasami Hiramatsu 	dst->args = zalloc(sizeof(struct perf_probe_arg) * src->nargs);
24420542bb9cSMasami Hiramatsu 	if (!dst->args)
24430542bb9cSMasami Hiramatsu 		goto out_err;
24440542bb9cSMasami Hiramatsu 	dst->nargs = src->nargs;
24450542bb9cSMasami Hiramatsu 
24460542bb9cSMasami Hiramatsu 	for (i = 0; i < src->nargs; i++)
24470542bb9cSMasami Hiramatsu 		if (perf_probe_arg__copy(&dst->args[i], &src->args[i]) < 0)
24480542bb9cSMasami Hiramatsu 			goto out_err;
24490542bb9cSMasami Hiramatsu 	return 0;
24500542bb9cSMasami Hiramatsu 
24510542bb9cSMasami Hiramatsu out_err:
24520542bb9cSMasami Hiramatsu 	clear_perf_probe_event(dst);
24530542bb9cSMasami Hiramatsu 	return -ENOMEM;
24540542bb9cSMasami Hiramatsu }
24550542bb9cSMasami Hiramatsu 
245692f6c72eSMasami Hiramatsu void clear_probe_trace_event(struct probe_trace_event *tev)
24574235b045SMasami Hiramatsu {
24580e60836bSSrikar Dronamraju 	struct probe_trace_arg_ref *ref, *next;
24594235b045SMasami Hiramatsu 	int i;
24604235b045SMasami Hiramatsu 
2461d8f9da24SArnaldo Carvalho de Melo 	zfree(&tev->event);
2462d8f9da24SArnaldo Carvalho de Melo 	zfree(&tev->group);
2463d8f9da24SArnaldo Carvalho de Melo 	zfree(&tev->point.symbol);
2464d8f9da24SArnaldo Carvalho de Melo 	zfree(&tev->point.realname);
2465d8f9da24SArnaldo Carvalho de Melo 	zfree(&tev->point.module);
24664235b045SMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
2467d8f9da24SArnaldo Carvalho de Melo 		zfree(&tev->args[i].name);
2468d8f9da24SArnaldo Carvalho de Melo 		zfree(&tev->args[i].value);
2469d8f9da24SArnaldo Carvalho de Melo 		zfree(&tev->args[i].type);
24704235b045SMasami Hiramatsu 		ref = tev->args[i].ref;
24714235b045SMasami Hiramatsu 		while (ref) {
24724235b045SMasami Hiramatsu 			next = ref->next;
24734235b045SMasami Hiramatsu 			free(ref);
24744235b045SMasami Hiramatsu 			ref = next;
24754235b045SMasami Hiramatsu 		}
24764235b045SMasami Hiramatsu 	}
2477d8f9da24SArnaldo Carvalho de Melo 	zfree(&tev->args);
24789e6124d9SMasami Hiramatsu 	tev->nargs = 0;
24794de189feSMasami Hiramatsu }
24804de189feSMasami Hiramatsu 
24819aaf5a5fSMasami Hiramatsu struct kprobe_blacklist_node {
24829aaf5a5fSMasami Hiramatsu 	struct list_head list;
248322a66551SYang Jihong 	u64 start;
248422a66551SYang Jihong 	u64 end;
24859aaf5a5fSMasami Hiramatsu 	char *symbol;
24869aaf5a5fSMasami Hiramatsu };
24879aaf5a5fSMasami Hiramatsu 
24889aaf5a5fSMasami Hiramatsu static void kprobe_blacklist__delete(struct list_head *blacklist)
24899aaf5a5fSMasami Hiramatsu {
24909aaf5a5fSMasami Hiramatsu 	struct kprobe_blacklist_node *node;
24919aaf5a5fSMasami Hiramatsu 
24929aaf5a5fSMasami Hiramatsu 	while (!list_empty(blacklist)) {
24939aaf5a5fSMasami Hiramatsu 		node = list_first_entry(blacklist,
24949aaf5a5fSMasami Hiramatsu 					struct kprobe_blacklist_node, list);
2495e56fbc9dSArnaldo Carvalho de Melo 		list_del_init(&node->list);
2496d8f9da24SArnaldo Carvalho de Melo 		zfree(&node->symbol);
24979aaf5a5fSMasami Hiramatsu 		free(node);
24989aaf5a5fSMasami Hiramatsu 	}
24999aaf5a5fSMasami Hiramatsu }
25009aaf5a5fSMasami Hiramatsu 
25019aaf5a5fSMasami Hiramatsu static int kprobe_blacklist__load(struct list_head *blacklist)
25029aaf5a5fSMasami Hiramatsu {
25039aaf5a5fSMasami Hiramatsu 	struct kprobe_blacklist_node *node;
25044605eab3SJiri Olsa 	const char *__debugfs = debugfs__mountpoint();
25059aaf5a5fSMasami Hiramatsu 	char buf[PATH_MAX], *p;
25069aaf5a5fSMasami Hiramatsu 	FILE *fp;
25079aaf5a5fSMasami Hiramatsu 	int ret;
25089aaf5a5fSMasami Hiramatsu 
25099aaf5a5fSMasami Hiramatsu 	if (__debugfs == NULL)
25109aaf5a5fSMasami Hiramatsu 		return -ENOTSUP;
25119aaf5a5fSMasami Hiramatsu 
25129aaf5a5fSMasami Hiramatsu 	ret = e_snprintf(buf, PATH_MAX, "%s/kprobes/blacklist", __debugfs);
25139aaf5a5fSMasami Hiramatsu 	if (ret < 0)
25149aaf5a5fSMasami Hiramatsu 		return ret;
25159aaf5a5fSMasami Hiramatsu 
25169aaf5a5fSMasami Hiramatsu 	fp = fopen(buf, "r");
25179aaf5a5fSMasami Hiramatsu 	if (!fp)
25189aaf5a5fSMasami Hiramatsu 		return -errno;
25199aaf5a5fSMasami Hiramatsu 
25209aaf5a5fSMasami Hiramatsu 	ret = 0;
25219aaf5a5fSMasami Hiramatsu 	while (fgets(buf, PATH_MAX, fp)) {
25229aaf5a5fSMasami Hiramatsu 		node = zalloc(sizeof(*node));
25239aaf5a5fSMasami Hiramatsu 		if (!node) {
25249aaf5a5fSMasami Hiramatsu 			ret = -ENOMEM;
25259aaf5a5fSMasami Hiramatsu 			break;
25269aaf5a5fSMasami Hiramatsu 		}
25279aaf5a5fSMasami Hiramatsu 		INIT_LIST_HEAD(&node->list);
25289aaf5a5fSMasami Hiramatsu 		list_add_tail(&node->list, blacklist);
252922a66551SYang Jihong 		if (sscanf(buf, "0x%" PRIx64 "-0x%" PRIx64, &node->start, &node->end) != 2) {
25309aaf5a5fSMasami Hiramatsu 			ret = -EINVAL;
25319aaf5a5fSMasami Hiramatsu 			break;
25329aaf5a5fSMasami Hiramatsu 		}
25339aaf5a5fSMasami Hiramatsu 		p = strchr(buf, '\t');
25349aaf5a5fSMasami Hiramatsu 		if (p) {
25359aaf5a5fSMasami Hiramatsu 			p++;
25369aaf5a5fSMasami Hiramatsu 			if (p[strlen(p) - 1] == '\n')
25379aaf5a5fSMasami Hiramatsu 				p[strlen(p) - 1] = '\0';
25389aaf5a5fSMasami Hiramatsu 		} else
25399aaf5a5fSMasami Hiramatsu 			p = (char *)"unknown";
25409aaf5a5fSMasami Hiramatsu 		node->symbol = strdup(p);
25419aaf5a5fSMasami Hiramatsu 		if (!node->symbol) {
25429aaf5a5fSMasami Hiramatsu 			ret = -ENOMEM;
25439aaf5a5fSMasami Hiramatsu 			break;
25449aaf5a5fSMasami Hiramatsu 		}
254522a66551SYang Jihong 		pr_debug2("Blacklist: 0x%" PRIx64 "-0x%" PRIx64 ", %s\n",
25469aaf5a5fSMasami Hiramatsu 			  node->start, node->end, node->symbol);
25479aaf5a5fSMasami Hiramatsu 		ret++;
25489aaf5a5fSMasami Hiramatsu 	}
25499aaf5a5fSMasami Hiramatsu 	if (ret < 0)
25509aaf5a5fSMasami Hiramatsu 		kprobe_blacklist__delete(blacklist);
25519aaf5a5fSMasami Hiramatsu 	fclose(fp);
25529aaf5a5fSMasami Hiramatsu 
25539aaf5a5fSMasami Hiramatsu 	return ret;
25549aaf5a5fSMasami Hiramatsu }
25559aaf5a5fSMasami Hiramatsu 
25569aaf5a5fSMasami Hiramatsu static struct kprobe_blacklist_node *
255722a66551SYang Jihong kprobe_blacklist__find_by_address(struct list_head *blacklist, u64 address)
25589aaf5a5fSMasami Hiramatsu {
25599aaf5a5fSMasami Hiramatsu 	struct kprobe_blacklist_node *node;
25609aaf5a5fSMasami Hiramatsu 
25619aaf5a5fSMasami Hiramatsu 	list_for_each_entry(node, blacklist, list) {
25622c29461eSLi Bin 		if (node->start <= address && address < node->end)
25639aaf5a5fSMasami Hiramatsu 			return node;
25649aaf5a5fSMasami Hiramatsu 	}
25659aaf5a5fSMasami Hiramatsu 
25669aaf5a5fSMasami Hiramatsu 	return NULL;
25679aaf5a5fSMasami Hiramatsu }
25689aaf5a5fSMasami Hiramatsu 
2569b031220dSMasami Hiramatsu static LIST_HEAD(kprobe_blacklist);
2570b031220dSMasami Hiramatsu 
2571b031220dSMasami Hiramatsu static void kprobe_blacklist__init(void)
2572b031220dSMasami Hiramatsu {
2573b031220dSMasami Hiramatsu 	if (!list_empty(&kprobe_blacklist))
2574b031220dSMasami Hiramatsu 		return;
2575b031220dSMasami Hiramatsu 
2576b031220dSMasami Hiramatsu 	if (kprobe_blacklist__load(&kprobe_blacklist) < 0)
2577b031220dSMasami Hiramatsu 		pr_debug("No kprobe blacklist support, ignored\n");
2578b031220dSMasami Hiramatsu }
2579b031220dSMasami Hiramatsu 
2580b031220dSMasami Hiramatsu static void kprobe_blacklist__release(void)
2581b031220dSMasami Hiramatsu {
2582b031220dSMasami Hiramatsu 	kprobe_blacklist__delete(&kprobe_blacklist);
2583b031220dSMasami Hiramatsu }
2584b031220dSMasami Hiramatsu 
258522a66551SYang Jihong static bool kprobe_blacklist__listed(u64 address)
2586b031220dSMasami Hiramatsu {
2587b031220dSMasami Hiramatsu 	return !!kprobe_blacklist__find_by_address(&kprobe_blacklist, address);
2588b031220dSMasami Hiramatsu }
2589b031220dSMasami Hiramatsu 
2590d350bd57SMasami Hiramatsu static int perf_probe_event__sprintf(const char *group, const char *event,
2591d350bd57SMasami Hiramatsu 				     struct perf_probe_event *pev,
2592ba7ecb02SMasami Hiramatsu 				     const char *module,
2593ba7ecb02SMasami Hiramatsu 				     struct strbuf *result)
2594278498d4SMasami Hiramatsu {
2595bf4d5f25SMasami Hiramatsu 	int i, ret;
2596909b0360SMasami Hiramatsu 	char *buf;
2597909b0360SMasami Hiramatsu 
2598909b0360SMasami Hiramatsu 	if (asprintf(&buf, "%s:%s", group, event) < 0)
2599909b0360SMasami Hiramatsu 		return -errno;
2600bf4d5f25SMasami Hiramatsu 	ret = strbuf_addf(result, "  %-20s (on ", buf);
2601909b0360SMasami Hiramatsu 	free(buf);
2602bf4d5f25SMasami Hiramatsu 	if (ret)
2603bf4d5f25SMasami Hiramatsu 		return ret;
2604278498d4SMasami Hiramatsu 
26054235b045SMasami Hiramatsu 	/* Synthesize only event probe point */
2606909b0360SMasami Hiramatsu 	buf = synthesize_perf_probe_point(&pev->point);
2607909b0360SMasami Hiramatsu 	if (!buf)
2608909b0360SMasami Hiramatsu 		return -ENOMEM;
2609bf4d5f25SMasami Hiramatsu 	ret = strbuf_addstr(result, buf);
2610909b0360SMasami Hiramatsu 	free(buf);
26114235b045SMasami Hiramatsu 
2612bf4d5f25SMasami Hiramatsu 	if (!ret && module)
2613bf4d5f25SMasami Hiramatsu 		ret = strbuf_addf(result, " in %s", module);
2614278498d4SMasami Hiramatsu 
2615bf4d5f25SMasami Hiramatsu 	if (!ret && pev->nargs > 0) {
2616bf4d5f25SMasami Hiramatsu 		ret = strbuf_add(result, " with", 5);
2617bf4d5f25SMasami Hiramatsu 		for (i = 0; !ret && i < pev->nargs; i++) {
2618909b0360SMasami Hiramatsu 			buf = synthesize_perf_probe_arg(&pev->args[i]);
2619909b0360SMasami Hiramatsu 			if (!buf)
2620909b0360SMasami Hiramatsu 				return -ENOMEM;
2621bf4d5f25SMasami Hiramatsu 			ret = strbuf_addf(result, " %s", buf);
2622909b0360SMasami Hiramatsu 			free(buf);
26237df2f329SMasami Hiramatsu 		}
2624278498d4SMasami Hiramatsu 	}
2625bf4d5f25SMasami Hiramatsu 	if (!ret)
2626bf4d5f25SMasami Hiramatsu 		ret = strbuf_addch(result, ')');
2627909b0360SMasami Hiramatsu 
2628bf4d5f25SMasami Hiramatsu 	return ret;
2629278498d4SMasami Hiramatsu }
2630278498d4SMasami Hiramatsu 
2631ba7ecb02SMasami Hiramatsu /* Show an event */
2632b02137ccSNamhyung Kim int show_perf_probe_event(const char *group, const char *event,
2633d350bd57SMasami Hiramatsu 			  struct perf_probe_event *pev,
2634ba7ecb02SMasami Hiramatsu 			  const char *module, bool use_stdout)
2635ba7ecb02SMasami Hiramatsu {
2636ba7ecb02SMasami Hiramatsu 	struct strbuf buf = STRBUF_INIT;
2637ba7ecb02SMasami Hiramatsu 	int ret;
2638ba7ecb02SMasami Hiramatsu 
2639d350bd57SMasami Hiramatsu 	ret = perf_probe_event__sprintf(group, event, pev, module, &buf);
2640ba7ecb02SMasami Hiramatsu 	if (ret >= 0) {
2641ba7ecb02SMasami Hiramatsu 		if (use_stdout)
2642ba7ecb02SMasami Hiramatsu 			printf("%s\n", buf.buf);
2643ba7ecb02SMasami Hiramatsu 		else
2644ba7ecb02SMasami Hiramatsu 			pr_info("%s\n", buf.buf);
2645ba7ecb02SMasami Hiramatsu 	}
2646ba7ecb02SMasami Hiramatsu 	strbuf_release(&buf);
2647ba7ecb02SMasami Hiramatsu 
2648ba7ecb02SMasami Hiramatsu 	return ret;
2649ba7ecb02SMasami Hiramatsu }
2650ba7ecb02SMasami Hiramatsu 
2651b6a89643SMasami Hiramatsu static bool filter_probe_trace_event(struct probe_trace_event *tev,
2652b6a89643SMasami Hiramatsu 				     struct strfilter *filter)
2653b6a89643SMasami Hiramatsu {
2654b6a89643SMasami Hiramatsu 	char tmp[128];
2655b6a89643SMasami Hiramatsu 
2656b6a89643SMasami Hiramatsu 	/* At first, check the event name itself */
2657b6a89643SMasami Hiramatsu 	if (strfilter__compare(filter, tev->event))
2658b6a89643SMasami Hiramatsu 		return true;
2659b6a89643SMasami Hiramatsu 
2660b6a89643SMasami Hiramatsu 	/* Next, check the combination of name and group */
2661b6a89643SMasami Hiramatsu 	if (e_snprintf(tmp, 128, "%s:%s", tev->group, tev->event) < 0)
2662b6a89643SMasami Hiramatsu 		return false;
2663b6a89643SMasami Hiramatsu 	return strfilter__compare(filter, tmp);
2664b6a89643SMasami Hiramatsu }
2665b6a89643SMasami Hiramatsu 
2666b6a89643SMasami Hiramatsu static int __show_perf_probe_events(int fd, bool is_kprobe,
2667b6a89643SMasami Hiramatsu 				    struct strfilter *filter)
26684de189feSMasami Hiramatsu {
2669225466f1SSrikar Dronamraju 	int ret = 0;
26700e60836bSSrikar Dronamraju 	struct probe_trace_event tev;
26714235b045SMasami Hiramatsu 	struct perf_probe_event pev;
26724de189feSMasami Hiramatsu 	struct strlist *rawlist;
26734de189feSMasami Hiramatsu 	struct str_node *ent;
26744de189feSMasami Hiramatsu 
26754235b045SMasami Hiramatsu 	memset(&tev, 0, sizeof(tev));
26764235b045SMasami Hiramatsu 	memset(&pev, 0, sizeof(pev));
267772041334SMasami Hiramatsu 
267892f6c72eSMasami Hiramatsu 	rawlist = probe_file__get_rawlist(fd);
2679146a1439SMasami Hiramatsu 	if (!rawlist)
26806eb08660SMasami Hiramatsu 		return -ENOMEM;
26814de189feSMasami Hiramatsu 
2682602a1f4dSArnaldo Carvalho de Melo 	strlist__for_each_entry(ent, rawlist) {
26830e60836bSSrikar Dronamraju 		ret = parse_probe_trace_command(ent->s, &tev);
2684146a1439SMasami Hiramatsu 		if (ret >= 0) {
2685b6a89643SMasami Hiramatsu 			if (!filter_probe_trace_event(&tev, filter))
2686b6a89643SMasami Hiramatsu 				goto next;
2687225466f1SSrikar Dronamraju 			ret = convert_to_perf_probe_event(&tev, &pev,
2688225466f1SSrikar Dronamraju 								is_kprobe);
2689ba7ecb02SMasami Hiramatsu 			if (ret < 0)
2690ba7ecb02SMasami Hiramatsu 				goto next;
2691d350bd57SMasami Hiramatsu 			ret = show_perf_probe_event(pev.group, pev.event,
2692d350bd57SMasami Hiramatsu 						    &pev, tev.point.module,
2693ba7ecb02SMasami Hiramatsu 						    true);
2694146a1439SMasami Hiramatsu 		}
2695b6a89643SMasami Hiramatsu next:
26964235b045SMasami Hiramatsu 		clear_perf_probe_event(&pev);
26970e60836bSSrikar Dronamraju 		clear_probe_trace_event(&tev);
2698146a1439SMasami Hiramatsu 		if (ret < 0)
2699146a1439SMasami Hiramatsu 			break;
27004de189feSMasami Hiramatsu 	}
27014de189feSMasami Hiramatsu 	strlist__delete(rawlist);
27027737af01SMasami Hiramatsu 	/* Cleanup cached debuginfo if needed */
27037737af01SMasami Hiramatsu 	debuginfo_cache__exit();
2704146a1439SMasami Hiramatsu 
2705146a1439SMasami Hiramatsu 	return ret;
27064de189feSMasami Hiramatsu }
27074de189feSMasami Hiramatsu 
2708225466f1SSrikar Dronamraju /* List up current perf-probe events */
2709b6a89643SMasami Hiramatsu int show_perf_probe_events(struct strfilter *filter)
2710225466f1SSrikar Dronamraju {
27115e45187cSMasami Hiramatsu 	int kp_fd, up_fd, ret;
2712225466f1SSrikar Dronamraju 
2713225466f1SSrikar Dronamraju 	setup_pager();
2714225466f1SSrikar Dronamraju 
27151f3736c9SMasami Hiramatsu 	if (probe_conf.cache)
27161f3736c9SMasami Hiramatsu 		return probe_cache__show_all_caches(filter);
27171f3736c9SMasami Hiramatsu 
27189bae1e8cSNamhyung Kim 	ret = init_probe_symbol_maps(false);
2719225466f1SSrikar Dronamraju 	if (ret < 0)
2720225466f1SSrikar Dronamraju 		return ret;
2721225466f1SSrikar Dronamraju 
272292f6c72eSMasami Hiramatsu 	ret = probe_file__open_both(&kp_fd, &up_fd, 0);
27235e45187cSMasami Hiramatsu 	if (ret < 0)
2724225466f1SSrikar Dronamraju 		return ret;
2725225466f1SSrikar Dronamraju 
272692f6c72eSMasami Hiramatsu 	if (kp_fd >= 0)
272792f6c72eSMasami Hiramatsu 		ret = __show_perf_probe_events(kp_fd, true, filter);
272892f6c72eSMasami Hiramatsu 	if (up_fd >= 0 && ret >= 0)
272992f6c72eSMasami Hiramatsu 		ret = __show_perf_probe_events(up_fd, false, filter);
273092f6c72eSMasami Hiramatsu 	if (kp_fd > 0)
273192f6c72eSMasami Hiramatsu 		close(kp_fd);
273292f6c72eSMasami Hiramatsu 	if (up_fd > 0)
273392f6c72eSMasami Hiramatsu 		close(up_fd);
27349bae1e8cSNamhyung Kim 	exit_probe_symbol_maps();
2735b498ce1fSMasami Hiramatsu 
2736146a1439SMasami Hiramatsu 	return ret;
2737f4d7da49SMasami Hiramatsu }
273850656eecSMasami Hiramatsu 
2739146a1439SMasami Hiramatsu static int get_new_event_name(char *buf, size_t len, const char *base,
2740e63c625aSMasami Hiramatsu 			      struct strlist *namelist, bool ret_event,
2741e63c625aSMasami Hiramatsu 			      bool allow_suffix)
2742b498ce1fSMasami Hiramatsu {
2743b498ce1fSMasami Hiramatsu 	int i, ret;
2744663b1151SMasami Hiramatsu 	char *p, *nbase;
274517f88fcdSMasami Hiramatsu 
27463099c026SNaveen N. Rao 	if (*base == '.')
27473099c026SNaveen N. Rao 		base++;
2748663b1151SMasami Hiramatsu 	nbase = strdup(base);
2749663b1151SMasami Hiramatsu 	if (!nbase)
2750663b1151SMasami Hiramatsu 		return -ENOMEM;
27513099c026SNaveen N. Rao 
2752a3110cd9SMasami Hiramatsu 	/* Cut off the dot suffixes (e.g. .const, .isra) and version suffixes */
2753a3110cd9SMasami Hiramatsu 	p = strpbrk(nbase, ".@");
2754663b1151SMasami Hiramatsu 	if (p && p != nbase)
2755663b1151SMasami Hiramatsu 		*p = '\0';
2756663b1151SMasami Hiramatsu 
2757663b1151SMasami Hiramatsu 	/* Try no suffix number */
2758e63c625aSMasami Hiramatsu 	ret = e_snprintf(buf, len, "%s%s", nbase, ret_event ? "__return" : "");
2759146a1439SMasami Hiramatsu 	if (ret < 0) {
2760c15ed444SDima Kogan 		pr_warning("snprintf() failed: %d; the event name nbase='%s' is too long\n", ret, nbase);
2761663b1151SMasami Hiramatsu 		goto out;
2762146a1439SMasami Hiramatsu 	}
276317f88fcdSMasami Hiramatsu 	if (!strlist__has_entry(namelist, buf))
2764663b1151SMasami Hiramatsu 		goto out;
276517f88fcdSMasami Hiramatsu 
2766d761b08bSMasami Hiramatsu 	if (!allow_suffix) {
276703e01f56SWang Nan 		pr_warning("Error: event \"%s\" already exists.\n"
276803e01f56SWang Nan 			   " Hint: Remove existing event by 'perf probe -d'\n"
276903e01f56SWang Nan 			   "       or force duplicates by 'perf probe -f'\n"
277003e01f56SWang Nan 			   "       or set 'force=yes' in BPF source.\n",
277103e01f56SWang Nan 			   buf);
2772663b1151SMasami Hiramatsu 		ret = -EEXIST;
2773663b1151SMasami Hiramatsu 		goto out;
2774d761b08bSMasami Hiramatsu 	}
2775d761b08bSMasami Hiramatsu 
277617f88fcdSMasami Hiramatsu 	/* Try to add suffix */
277717f88fcdSMasami Hiramatsu 	for (i = 1; i < MAX_EVENT_INDEX; i++) {
2778663b1151SMasami Hiramatsu 		ret = e_snprintf(buf, len, "%s_%d", nbase, i);
2779146a1439SMasami Hiramatsu 		if (ret < 0) {
27805f03cba4SMasami Hiramatsu 			pr_debug("snprintf() failed: %d\n", ret);
2781663b1151SMasami Hiramatsu 			goto out;
2782146a1439SMasami Hiramatsu 		}
2783b498ce1fSMasami Hiramatsu 		if (!strlist__has_entry(namelist, buf))
2784b498ce1fSMasami Hiramatsu 			break;
2785b498ce1fSMasami Hiramatsu 	}
2786146a1439SMasami Hiramatsu 	if (i == MAX_EVENT_INDEX) {
2787146a1439SMasami Hiramatsu 		pr_warning("Too many events are on the same function.\n");
2788146a1439SMasami Hiramatsu 		ret = -ERANGE;
2789b498ce1fSMasami Hiramatsu 	}
2790b498ce1fSMasami Hiramatsu 
2791663b1151SMasami Hiramatsu out:
2792663b1151SMasami Hiramatsu 	free(nbase);
27939f5c6d87SMasami Hiramatsu 
27949f5c6d87SMasami Hiramatsu 	/* Final validation */
27959f5c6d87SMasami Hiramatsu 	if (ret >= 0 && !is_c_func_name(buf)) {
27969f5c6d87SMasami Hiramatsu 		pr_warning("Internal error: \"%s\" is an invalid event name.\n",
27979f5c6d87SMasami Hiramatsu 			   buf);
27989f5c6d87SMasami Hiramatsu 		ret = -EINVAL;
27999f5c6d87SMasami Hiramatsu 	}
28009f5c6d87SMasami Hiramatsu 
2801146a1439SMasami Hiramatsu 	return ret;
2802146a1439SMasami Hiramatsu }
2803146a1439SMasami Hiramatsu 
280479702f61SMasami Hiramatsu /* Warn if the current kernel's uprobe implementation is old */
280579702f61SMasami Hiramatsu static void warn_uprobe_event_compat(struct probe_trace_event *tev)
280679702f61SMasami Hiramatsu {
280779702f61SMasami Hiramatsu 	int i;
280879702f61SMasami Hiramatsu 	char *buf = synthesize_probe_trace_command(tev);
28095a5e3d3cSRavi Bangoria 	struct probe_trace_point *tp = &tev->point;
28105a5e3d3cSRavi Bangoria 
28115a5e3d3cSRavi Bangoria 	if (tp->ref_ctr_offset && !uprobe_ref_ctr_is_supported()) {
28125a5e3d3cSRavi Bangoria 		pr_warning("A semaphore is associated with %s:%s and "
28135a5e3d3cSRavi Bangoria 			   "seems your kernel doesn't support it.\n",
28145a5e3d3cSRavi Bangoria 			   tev->group, tev->event);
28155a5e3d3cSRavi Bangoria 	}
281679702f61SMasami Hiramatsu 
281779702f61SMasami Hiramatsu 	/* Old uprobe event doesn't support memory dereference */
281879702f61SMasami Hiramatsu 	if (!tev->uprobes || tev->nargs == 0 || !buf)
281979702f61SMasami Hiramatsu 		goto out;
282079702f61SMasami Hiramatsu 
2821e8ca4f0fSMasami Hiramatsu 	for (i = 0; i < tev->nargs; i++) {
2822e8ca4f0fSMasami Hiramatsu 		if (strchr(tev->args[i].value, '@')) {
2823e8ca4f0fSMasami Hiramatsu 			pr_warning("%s accesses a variable by symbol name, but that is not supported for user application probe.\n",
282479702f61SMasami Hiramatsu 				   tev->args[i].value);
282579702f61SMasami Hiramatsu 			break;
282679702f61SMasami Hiramatsu 		}
2827e8ca4f0fSMasami Hiramatsu 		if (strglobmatch(tev->args[i].value, "[$+-]*")) {
2828e8ca4f0fSMasami Hiramatsu 			pr_warning("Please upgrade your kernel to at least 3.14 to have access to feature %s\n",
2829e8ca4f0fSMasami Hiramatsu 				   tev->args[i].value);
2830e8ca4f0fSMasami Hiramatsu 			break;
2831e8ca4f0fSMasami Hiramatsu 		}
2832e8ca4f0fSMasami Hiramatsu 	}
283379702f61SMasami Hiramatsu out:
283479702f61SMasami Hiramatsu 	free(buf);
283579702f61SMasami Hiramatsu }
283679702f61SMasami Hiramatsu 
2837a3c9de62SMasami Hiramatsu /* Set new name from original perf_probe_event and namelist */
2838a3c9de62SMasami Hiramatsu static int probe_trace_event__set_name(struct probe_trace_event *tev,
2839a3c9de62SMasami Hiramatsu 				       struct perf_probe_event *pev,
2840a3c9de62SMasami Hiramatsu 				       struct strlist *namelist,
2841a3c9de62SMasami Hiramatsu 				       bool allow_suffix)
2842a3c9de62SMasami Hiramatsu {
2843a3c9de62SMasami Hiramatsu 	const char *event, *group;
2844a3c9de62SMasami Hiramatsu 	char buf[64];
2845a3c9de62SMasami Hiramatsu 	int ret;
2846a3c9de62SMasami Hiramatsu 
2847bc062230SMasami Hiramatsu 	/* If probe_event or trace_event already have the name, reuse it */
284842bba263SMasami Hiramatsu 	if (pev->event && !pev->sdt)
2849a3c9de62SMasami Hiramatsu 		event = pev->event;
2850bc062230SMasami Hiramatsu 	else if (tev->event)
2851bc062230SMasami Hiramatsu 		event = tev->event;
2852bc062230SMasami Hiramatsu 	else {
2853bc062230SMasami Hiramatsu 		/* Or generate new one from probe point */
2854da15bd9dSWang Nan 		if (pev->point.function &&
2855da15bd9dSWang Nan 			(strncmp(pev->point.function, "0x", 2) != 0) &&
2856da15bd9dSWang Nan 			!strisglob(pev->point.function))
2857a3c9de62SMasami Hiramatsu 			event = pev->point.function;
2858a3c9de62SMasami Hiramatsu 		else
2859a3c9de62SMasami Hiramatsu 			event = tev->point.realname;
2860bc062230SMasami Hiramatsu 	}
286142bba263SMasami Hiramatsu 	if (pev->group && !pev->sdt)
2862a3c9de62SMasami Hiramatsu 		group = pev->group;
2863bc062230SMasami Hiramatsu 	else if (tev->group)
2864bc062230SMasami Hiramatsu 		group = tev->group;
2865a3c9de62SMasami Hiramatsu 	else
2866a3c9de62SMasami Hiramatsu 		group = PERFPROBE_GROUP;
2867a3c9de62SMasami Hiramatsu 
2868a3c9de62SMasami Hiramatsu 	/* Get an unused new event name */
2869a529bec0SDima Kogan 	ret = get_new_event_name(buf, sizeof(buf), event, namelist,
2870e63c625aSMasami Hiramatsu 				 tev->point.retprobe, allow_suffix);
2871a3c9de62SMasami Hiramatsu 	if (ret < 0)
2872a3c9de62SMasami Hiramatsu 		return ret;
2873a3c9de62SMasami Hiramatsu 
2874a3c9de62SMasami Hiramatsu 	event = buf;
2875a3c9de62SMasami Hiramatsu 
2876a3c9de62SMasami Hiramatsu 	tev->event = strdup(event);
2877a3c9de62SMasami Hiramatsu 	tev->group = strdup(group);
2878a3c9de62SMasami Hiramatsu 	if (tev->event == NULL || tev->group == NULL)
2879a3c9de62SMasami Hiramatsu 		return -ENOMEM;
2880a3c9de62SMasami Hiramatsu 
288172363540SMasami Hiramatsu 	/*
288272363540SMasami Hiramatsu 	 * Add new event name to namelist if multiprobe event is NOT
288372363540SMasami Hiramatsu 	 * supported, since we have to use new event name for following
288472363540SMasami Hiramatsu 	 * probes in that case.
288572363540SMasami Hiramatsu 	 */
288672363540SMasami Hiramatsu 	if (!multiprobe_event_is_supported())
2887a3c9de62SMasami Hiramatsu 		strlist__add(namelist, event);
2888a3c9de62SMasami Hiramatsu 	return 0;
2889a3c9de62SMasami Hiramatsu }
2890a3c9de62SMasami Hiramatsu 
28911de7b8bfSMasami Hiramatsu static int __open_probe_file_and_namelist(bool uprobe,
28921de7b8bfSMasami Hiramatsu 					  struct strlist **namelist)
289350656eecSMasami Hiramatsu {
28941de7b8bfSMasami Hiramatsu 	int fd;
289550656eecSMasami Hiramatsu 
28961de7b8bfSMasami Hiramatsu 	fd = probe_file__open(PF_FL_RW | (uprobe ? PF_FL_UPROBE : 0));
289792f6c72eSMasami Hiramatsu 	if (fd < 0)
2898146a1439SMasami Hiramatsu 		return fd;
28995e45187cSMasami Hiramatsu 
2900b498ce1fSMasami Hiramatsu 	/* Get current event names */
29011de7b8bfSMasami Hiramatsu 	*namelist = probe_file__get_namelist(fd);
29021de7b8bfSMasami Hiramatsu 	if (!(*namelist)) {
2903146a1439SMasami Hiramatsu 		pr_debug("Failed to get current event list.\n");
29041de7b8bfSMasami Hiramatsu 		close(fd);
29051de7b8bfSMasami Hiramatsu 		return -ENOMEM;
2906146a1439SMasami Hiramatsu 	}
29071de7b8bfSMasami Hiramatsu 	return fd;
29081de7b8bfSMasami Hiramatsu }
29091de7b8bfSMasami Hiramatsu 
29101de7b8bfSMasami Hiramatsu static int __add_probe_trace_events(struct perf_probe_event *pev,
29111de7b8bfSMasami Hiramatsu 				     struct probe_trace_event *tevs,
29121de7b8bfSMasami Hiramatsu 				     int ntevs, bool allow_suffix)
29131de7b8bfSMasami Hiramatsu {
29141de7b8bfSMasami Hiramatsu 	int i, fd[2] = {-1, -1}, up, ret;
29151de7b8bfSMasami Hiramatsu 	struct probe_trace_event *tev = NULL;
29161de7b8bfSMasami Hiramatsu 	struct probe_cache *cache = NULL;
29171de7b8bfSMasami Hiramatsu 	struct strlist *namelist[2] = {NULL, NULL};
2918544abd44SKrister Johansen 	struct nscookie nsc;
29191de7b8bfSMasami Hiramatsu 
29201de7b8bfSMasami Hiramatsu 	up = pev->uprobes ? 1 : 0;
29211de7b8bfSMasami Hiramatsu 	fd[up] = __open_probe_file_and_namelist(up, &namelist[up]);
29221de7b8bfSMasami Hiramatsu 	if (fd[up] < 0)
29231de7b8bfSMasami Hiramatsu 		return fd[up];
292450656eecSMasami Hiramatsu 
2925146a1439SMasami Hiramatsu 	ret = 0;
292602b95dadSMasami Hiramatsu 	for (i = 0; i < ntevs; i++) {
29274235b045SMasami Hiramatsu 		tev = &tevs[i];
29281de7b8bfSMasami Hiramatsu 		up = tev->uprobes ? 1 : 0;
29291de7b8bfSMasami Hiramatsu 		if (fd[up] == -1) {	/* Open the kprobe/uprobe_events */
29301de7b8bfSMasami Hiramatsu 			fd[up] = __open_probe_file_and_namelist(up,
29311de7b8bfSMasami Hiramatsu 								&namelist[up]);
29321de7b8bfSMasami Hiramatsu 			if (fd[up] < 0)
29331de7b8bfSMasami Hiramatsu 				goto close_out;
29341de7b8bfSMasami Hiramatsu 		}
2935b031220dSMasami Hiramatsu 		/* Skip if the symbol is out of .text or blacklisted */
2936bc062230SMasami Hiramatsu 		if (!tev->point.symbol && !pev->uprobes)
29375a51fcd1SMasami Hiramatsu 			continue;
29389aaf5a5fSMasami Hiramatsu 
2939a3c9de62SMasami Hiramatsu 		/* Set new name for tev (and update namelist) */
29401de7b8bfSMasami Hiramatsu 		ret = probe_trace_event__set_name(tev, pev, namelist[up],
2941a3c9de62SMasami Hiramatsu 						  allow_suffix);
2942146a1439SMasami Hiramatsu 		if (ret < 0)
2943146a1439SMasami Hiramatsu 			break;
29444235b045SMasami Hiramatsu 
2945544abd44SKrister Johansen 		nsinfo__mountns_enter(pev->nsi, &nsc);
29461de7b8bfSMasami Hiramatsu 		ret = probe_file__add_event(fd[up], tev);
2947544abd44SKrister Johansen 		nsinfo__mountns_exit(&nsc);
2948146a1439SMasami Hiramatsu 		if (ret < 0)
2949146a1439SMasami Hiramatsu 			break;
29504235b045SMasami Hiramatsu 
2951d761b08bSMasami Hiramatsu 		/*
2952d761b08bSMasami Hiramatsu 		 * Probes after the first probe which comes from same
2953d761b08bSMasami Hiramatsu 		 * user input are always allowed to add suffix, because
2954d761b08bSMasami Hiramatsu 		 * there might be several addresses corresponding to
2955d761b08bSMasami Hiramatsu 		 * one code line.
2956d761b08bSMasami Hiramatsu 		 */
2957d761b08bSMasami Hiramatsu 		allow_suffix = true;
295850656eecSMasami Hiramatsu 	}
295979702f61SMasami Hiramatsu 	if (ret == -EINVAL && pev->uprobes)
296079702f61SMasami Hiramatsu 		warn_uprobe_event_compat(tev);
29612fd457a3SMasami Hiramatsu 	if (ret == 0 && probe_conf.cache) {
2962f045b8c4SKrister Johansen 		cache = probe_cache__new(pev->target, pev->nsi);
29632fd457a3SMasami Hiramatsu 		if (!cache ||
29642fd457a3SMasami Hiramatsu 		    probe_cache__add_entry(cache, pev, tevs, ntevs) < 0 ||
29652fd457a3SMasami Hiramatsu 		    probe_cache__commit(cache) < 0)
29662fd457a3SMasami Hiramatsu 			pr_warning("Failed to add event to probe cache\n");
29672fd457a3SMasami Hiramatsu 		probe_cache__delete(cache);
29682fd457a3SMasami Hiramatsu 	}
2969146a1439SMasami Hiramatsu 
2970ae2cb1acSMasami Hiramatsu close_out:
29711de7b8bfSMasami Hiramatsu 	for (up = 0; up < 2; up++) {
29721de7b8bfSMasami Hiramatsu 		strlist__delete(namelist[up]);
29731de7b8bfSMasami Hiramatsu 		if (fd[up] >= 0)
29741de7b8bfSMasami Hiramatsu 			close(fd[up]);
29751de7b8bfSMasami Hiramatsu 	}
2976146a1439SMasami Hiramatsu 	return ret;
297750656eecSMasami Hiramatsu }
2978fa28244dSMasami Hiramatsu 
29796bb536ccSWang Nan static int find_probe_functions(struct map *map, char *name,
29806bb536ccSWang Nan 				struct symbol **syms)
2981eb948e50SMasami Hiramatsu {
2982564c62a4SNamhyung Kim 	int found = 0;
29830a3873a8SArnaldo Carvalho de Melo 	struct symbol *sym;
29844c859351SMasami Hiramatsu 	struct rb_node *tmp;
29854b3a2716SMasami Hiramatsu 	const char *norm, *ver;
29864b3a2716SMasami Hiramatsu 	char *buf = NULL;
2987c588d158SMasami Hiramatsu 	bool cut_version = true;
2988564c62a4SNamhyung Kim 
2989be39db9fSArnaldo Carvalho de Melo 	if (map__load(map) < 0)
2990f4f1c429SMasami Hiramatsu 		return -EACCES;	/* Possible permission error to load symbols */
299175e4a2a6SWang Nan 
2992c588d158SMasami Hiramatsu 	/* If user gives a version, don't cut off the version from symbols */
2993c588d158SMasami Hiramatsu 	if (strchr(name, '@'))
2994c588d158SMasami Hiramatsu 		cut_version = false;
2995c588d158SMasami Hiramatsu 
29964c859351SMasami Hiramatsu 	map__for_each_symbol(map, sym, tmp) {
29974b3a2716SMasami Hiramatsu 		norm = arch__normalize_symbol_name(sym->name);
29984b3a2716SMasami Hiramatsu 		if (!norm)
29994b3a2716SMasami Hiramatsu 			continue;
30004b3a2716SMasami Hiramatsu 
3001c588d158SMasami Hiramatsu 		if (cut_version) {
30024b3a2716SMasami Hiramatsu 			/* We don't care about default symbol or not */
30034b3a2716SMasami Hiramatsu 			ver = strchr(norm, '@');
30044b3a2716SMasami Hiramatsu 			if (ver) {
30054b3a2716SMasami Hiramatsu 				buf = strndup(norm, ver - norm);
30064b3a2716SMasami Hiramatsu 				if (!buf)
30074b3a2716SMasami Hiramatsu 					return -ENOMEM;
30084b3a2716SMasami Hiramatsu 				norm = buf;
30094b3a2716SMasami Hiramatsu 			}
3010c588d158SMasami Hiramatsu 		}
3011c588d158SMasami Hiramatsu 
30124b3a2716SMasami Hiramatsu 		if (strglobmatch(norm, name)) {
3013564c62a4SNamhyung Kim 			found++;
30146bb536ccSWang Nan 			if (syms && found < probe_conf.max_probes)
30156bb536ccSWang Nan 				syms[found - 1] = sym;
30166bb536ccSWang Nan 		}
30174b3a2716SMasami Hiramatsu 		if (buf)
30184b3a2716SMasami Hiramatsu 			zfree(&buf);
3019eb948e50SMasami Hiramatsu 	}
3020564c62a4SNamhyung Kim 
3021564c62a4SNamhyung Kim 	return found;
3022eb948e50SMasami Hiramatsu }
3023eb948e50SMasami Hiramatsu 
30247b6ff0bdSNaveen N. Rao void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused,
30257b6ff0bdSNaveen N. Rao 				struct probe_trace_event *tev __maybe_unused,
30260b3c2264SNaveen N. Rao 				struct map *map __maybe_unused,
30270b3c2264SNaveen N. Rao 				struct symbol *sym __maybe_unused) { }
30287b6ff0bdSNaveen N. Rao 
3029f4f1c429SMasami Hiramatsu 
3030f4f1c429SMasami Hiramatsu static void pr_kallsyms_access_error(void)
3031f4f1c429SMasami Hiramatsu {
3032f4f1c429SMasami Hiramatsu 	pr_err("Please ensure you can read the /proc/kallsyms symbol addresses.\n"
3033f4f1c429SMasami Hiramatsu 	       "If /proc/sys/kernel/kptr_restrict is '2', you can not read\n"
3034f4f1c429SMasami Hiramatsu 	       "kernel symbol addresses even if you are a superuser. Please change\n"
3035f4f1c429SMasami Hiramatsu 	       "it to '1'. If kptr_restrict is '1', the superuser can read the\n"
3036f4f1c429SMasami Hiramatsu 	       "symbol addresses.\n"
3037f4f1c429SMasami Hiramatsu 	       "In that case, please run this command again with sudo.\n");
3038f4f1c429SMasami Hiramatsu }
3039f4f1c429SMasami Hiramatsu 
3040eb948e50SMasami Hiramatsu /*
3041eb948e50SMasami Hiramatsu  * Find probe function addresses from map.
3042eb948e50SMasami Hiramatsu  * Return an error or the number of found probe_trace_event
3043eb948e50SMasami Hiramatsu  */
3044eb948e50SMasami Hiramatsu static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
3045ddb2f58fSMasami Hiramatsu 					    struct probe_trace_event **tevs)
3046eb948e50SMasami Hiramatsu {
3047eb948e50SMasami Hiramatsu 	struct map *map = NULL;
3048eb948e50SMasami Hiramatsu 	struct ref_reloc_sym *reloc_sym = NULL;
3049eb948e50SMasami Hiramatsu 	struct symbol *sym;
30506bb536ccSWang Nan 	struct symbol **syms = NULL;
3051eb948e50SMasami Hiramatsu 	struct probe_trace_event *tev;
3052eb948e50SMasami Hiramatsu 	struct perf_probe_point *pp = &pev->point;
3053eb948e50SMasami Hiramatsu 	struct probe_trace_point *tp;
3054564c62a4SNamhyung Kim 	int num_matched_functions;
3055b031220dSMasami Hiramatsu 	int ret, i, j, skipped = 0;
3056c61fb959SRavi Bangoria 	char *mod_name;
3057eb948e50SMasami Hiramatsu 
3058544abd44SKrister Johansen 	map = get_target_map(pev->target, pev->nsi, pev->uprobes);
3059eb948e50SMasami Hiramatsu 	if (!map) {
3060eb948e50SMasami Hiramatsu 		ret = -EINVAL;
3061eb948e50SMasami Hiramatsu 		goto out;
3062eb948e50SMasami Hiramatsu 	}
3063eb948e50SMasami Hiramatsu 
30646bb536ccSWang Nan 	syms = malloc(sizeof(struct symbol *) * probe_conf.max_probes);
30656bb536ccSWang Nan 	if (!syms) {
30666bb536ccSWang Nan 		ret = -ENOMEM;
30676bb536ccSWang Nan 		goto out;
30686bb536ccSWang Nan 	}
30696bb536ccSWang Nan 
3070eb948e50SMasami Hiramatsu 	/*
3071eb948e50SMasami Hiramatsu 	 * Load matched symbols: Since the different local symbols may have
3072eb948e50SMasami Hiramatsu 	 * same name but different addresses, this lists all the symbols.
3073eb948e50SMasami Hiramatsu 	 */
30746bb536ccSWang Nan 	num_matched_functions = find_probe_functions(map, pp->function, syms);
30754b3a2716SMasami Hiramatsu 	if (num_matched_functions <= 0) {
3076f4f1c429SMasami Hiramatsu 		if (num_matched_functions == -EACCES) {
3077f4f1c429SMasami Hiramatsu 			pr_err("Failed to load symbols from %s\n",
3078f4f1c429SMasami Hiramatsu 			       pev->target ?: "/proc/kallsyms");
3079f4f1c429SMasami Hiramatsu 			if (pev->target)
3080f4f1c429SMasami Hiramatsu 				pr_err("Please ensure the file is not stripped.\n");
3081f4f1c429SMasami Hiramatsu 			else
3082f4f1c429SMasami Hiramatsu 				pr_kallsyms_access_error();
3083f4f1c429SMasami Hiramatsu 		} else
3084eb948e50SMasami Hiramatsu 			pr_err("Failed to find symbol %s in %s\n", pp->function,
308544225521SMasami Hiramatsu 				pev->target ? : "kernel");
3086eb948e50SMasami Hiramatsu 		ret = -ENOENT;
3087eb948e50SMasami Hiramatsu 		goto out;
3088ddb2f58fSMasami Hiramatsu 	} else if (num_matched_functions > probe_conf.max_probes) {
3089eb948e50SMasami Hiramatsu 		pr_err("Too many functions matched in %s\n",
309044225521SMasami Hiramatsu 			pev->target ? : "kernel");
3091eb948e50SMasami Hiramatsu 		ret = -E2BIG;
3092eb948e50SMasami Hiramatsu 		goto out;
3093eb948e50SMasami Hiramatsu 	}
3094eb948e50SMasami Hiramatsu 
30951a8ac29cSMasami Hiramatsu 	/* Note that the symbols in the kmodule are not relocated */
30967ab31d94SNaveen N. Rao 	if (!pev->uprobes && !pev->target &&
30977ab31d94SNaveen N. Rao 			(!pp->retprobe || kretprobe_offset_is_supported())) {
309880526491SMasami Hiramatsu 		reloc_sym = kernel_get_ref_reloc_sym(NULL);
3099eb948e50SMasami Hiramatsu 		if (!reloc_sym) {
310041ca1d1eSRavi Bangoria 			pr_warning("Relocated base symbol is not found! "
310141ca1d1eSRavi Bangoria 				   "Check /proc/sys/kernel/kptr_restrict\n"
310241ca1d1eSRavi Bangoria 				   "and /proc/sys/kernel/perf_event_paranoid. "
310341ca1d1eSRavi Bangoria 				   "Or run as privileged perf user.\n\n");
3104eb948e50SMasami Hiramatsu 			ret = -EINVAL;
3105eb948e50SMasami Hiramatsu 			goto out;
3106eb948e50SMasami Hiramatsu 		}
3107eb948e50SMasami Hiramatsu 	}
3108eb948e50SMasami Hiramatsu 
3109eb948e50SMasami Hiramatsu 	/* Setup result trace-probe-events */
3110eb948e50SMasami Hiramatsu 	*tevs = zalloc(sizeof(*tev) * num_matched_functions);
3111eb948e50SMasami Hiramatsu 	if (!*tevs) {
3112eb948e50SMasami Hiramatsu 		ret = -ENOMEM;
3113eb948e50SMasami Hiramatsu 		goto out;
3114eb948e50SMasami Hiramatsu 	}
3115eb948e50SMasami Hiramatsu 
3116eb948e50SMasami Hiramatsu 	ret = 0;
3117564c62a4SNamhyung Kim 
31186bb536ccSWang Nan 	for (j = 0; j < num_matched_functions; j++) {
31196bb536ccSWang Nan 		sym = syms[j];
31206bb536ccSWang Nan 
31214624f199SZechuan Chen 		if (sym->type != STT_FUNC)
31224624f199SZechuan Chen 			continue;
31234624f199SZechuan Chen 
312426bbf45fSMasami Hiramatsu 		/* There can be duplicated symbols in the map */
312526bbf45fSMasami Hiramatsu 		for (i = 0; i < j; i++)
312626bbf45fSMasami Hiramatsu 			if (sym->start == syms[i]->start) {
312726bbf45fSMasami Hiramatsu 				pr_debug("Found duplicated symbol %s @ %" PRIx64 "\n",
312826bbf45fSMasami Hiramatsu 					 sym->name, sym->start);
312926bbf45fSMasami Hiramatsu 				break;
313026bbf45fSMasami Hiramatsu 			}
313126bbf45fSMasami Hiramatsu 		if (i != j)
313226bbf45fSMasami Hiramatsu 			continue;
313326bbf45fSMasami Hiramatsu 
3134eb948e50SMasami Hiramatsu 		tev = (*tevs) + ret;
3135eb948e50SMasami Hiramatsu 		tp = &tev->point;
3136eb948e50SMasami Hiramatsu 		if (ret == num_matched_functions) {
3137eb948e50SMasami Hiramatsu 			pr_warning("Too many symbols are listed. Skip it.\n");
3138eb948e50SMasami Hiramatsu 			break;
3139eb948e50SMasami Hiramatsu 		}
3140eb948e50SMasami Hiramatsu 		ret++;
3141eb948e50SMasami Hiramatsu 
3142eb948e50SMasami Hiramatsu 		if (pp->offset > sym->end - sym->start) {
3143eb948e50SMasami Hiramatsu 			pr_warning("Offset %ld is bigger than the size of %s\n",
3144eb948e50SMasami Hiramatsu 				   pp->offset, sym->name);
3145eb948e50SMasami Hiramatsu 			ret = -ENOENT;
3146eb948e50SMasami Hiramatsu 			goto err_out;
3147eb948e50SMasami Hiramatsu 		}
3148eb948e50SMasami Hiramatsu 		/* Add one probe point */
314978a1f7cdSIan Rogers 		tp->address = map__unmap_ip(map, sym->start) + pp->offset;
31501a8ac29cSMasami Hiramatsu 
31511a8ac29cSMasami Hiramatsu 		/* Check the kprobe (not in module) is within .text  */
31521a8ac29cSMasami Hiramatsu 		if (!pev->uprobes && !pev->target &&
3153b031220dSMasami Hiramatsu 		    kprobe_warn_out_range(sym->name, tp->address)) {
3154b031220dSMasami Hiramatsu 			tp->symbol = NULL;	/* Skip it */
3155b031220dSMasami Hiramatsu 			skipped++;
3156b031220dSMasami Hiramatsu 		} else if (reloc_sym) {
3157eb948e50SMasami Hiramatsu 			tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out);
3158eb948e50SMasami Hiramatsu 			tp->offset = tp->address - reloc_sym->addr;
3159eb948e50SMasami Hiramatsu 		} else {
3160eb948e50SMasami Hiramatsu 			tp->symbol = strdup_or_goto(sym->name, nomem_out);
3161eb948e50SMasami Hiramatsu 			tp->offset = pp->offset;
3162eb948e50SMasami Hiramatsu 		}
31636bb536ccSWang Nan 		tp->realname = strdup_or_goto(sym->name, nomem_out);
31646bb536ccSWang Nan 
3165eb948e50SMasami Hiramatsu 		tp->retprobe = pp->retprobe;
3166c61fb959SRavi Bangoria 		if (pev->target) {
3167c61fb959SRavi Bangoria 			if (pev->uprobes) {
316844225521SMasami Hiramatsu 				tev->point.module = strdup_or_goto(pev->target,
316944225521SMasami Hiramatsu 								   nomem_out);
3170c61fb959SRavi Bangoria 			} else {
3171c61fb959SRavi Bangoria 				mod_name = find_module_name(pev->target);
3172c61fb959SRavi Bangoria 				tev->point.module =
3173c61fb959SRavi Bangoria 					strdup(mod_name ? mod_name : pev->target);
3174c61fb959SRavi Bangoria 				free(mod_name);
3175c61fb959SRavi Bangoria 				if (!tev->point.module)
3176c61fb959SRavi Bangoria 					goto nomem_out;
3177c61fb959SRavi Bangoria 			}
3178c61fb959SRavi Bangoria 		}
3179eb948e50SMasami Hiramatsu 		tev->uprobes = pev->uprobes;
3180eb948e50SMasami Hiramatsu 		tev->nargs = pev->nargs;
3181eb948e50SMasami Hiramatsu 		if (tev->nargs) {
3182eb948e50SMasami Hiramatsu 			tev->args = zalloc(sizeof(struct probe_trace_arg) *
3183eb948e50SMasami Hiramatsu 					   tev->nargs);
3184eb948e50SMasami Hiramatsu 			if (tev->args == NULL)
3185eb948e50SMasami Hiramatsu 				goto nomem_out;
3186eb948e50SMasami Hiramatsu 		}
3187eb948e50SMasami Hiramatsu 		for (i = 0; i < tev->nargs; i++) {
3188eb948e50SMasami Hiramatsu 			if (pev->args[i].name)
3189eb948e50SMasami Hiramatsu 				tev->args[i].name =
3190eb948e50SMasami Hiramatsu 					strdup_or_goto(pev->args[i].name,
3191eb948e50SMasami Hiramatsu 							nomem_out);
3192eb948e50SMasami Hiramatsu 
3193eb948e50SMasami Hiramatsu 			tev->args[i].value = strdup_or_goto(pev->args[i].var,
3194eb948e50SMasami Hiramatsu 							    nomem_out);
3195eb948e50SMasami Hiramatsu 			if (pev->args[i].type)
3196eb948e50SMasami Hiramatsu 				tev->args[i].type =
3197eb948e50SMasami Hiramatsu 					strdup_or_goto(pev->args[i].type,
3198eb948e50SMasami Hiramatsu 							nomem_out);
3199eb948e50SMasami Hiramatsu 		}
32000b3c2264SNaveen N. Rao 		arch__fix_tev_from_maps(pev, tev, map, sym);
3201eb948e50SMasami Hiramatsu 	}
3202b031220dSMasami Hiramatsu 	if (ret == skipped) {
3203b031220dSMasami Hiramatsu 		ret = -ENOENT;
3204b031220dSMasami Hiramatsu 		goto err_out;
3205b031220dSMasami Hiramatsu 	}
3206eb948e50SMasami Hiramatsu 
3207eb948e50SMasami Hiramatsu out:
3208eebc509bSMasami Hiramatsu 	map__put(map);
32096bb536ccSWang Nan 	free(syms);
3210eb948e50SMasami Hiramatsu 	return ret;
3211eb948e50SMasami Hiramatsu 
3212eb948e50SMasami Hiramatsu nomem_out:
3213eb948e50SMasami Hiramatsu 	ret = -ENOMEM;
3214eb948e50SMasami Hiramatsu err_out:
3215eb948e50SMasami Hiramatsu 	clear_probe_trace_events(*tevs, num_matched_functions);
3216eb948e50SMasami Hiramatsu 	zfree(tevs);
3217eb948e50SMasami Hiramatsu 	goto out;
3218eb948e50SMasami Hiramatsu }
3219eb948e50SMasami Hiramatsu 
3220da15bd9dSWang Nan static int try_to_find_absolute_address(struct perf_probe_event *pev,
3221da15bd9dSWang Nan 					struct probe_trace_event **tevs)
3222da15bd9dSWang Nan {
3223da15bd9dSWang Nan 	struct perf_probe_point *pp = &pev->point;
3224da15bd9dSWang Nan 	struct probe_trace_event *tev;
3225da15bd9dSWang Nan 	struct probe_trace_point *tp;
3226da15bd9dSWang Nan 	int i, err;
3227da15bd9dSWang Nan 
3228da15bd9dSWang Nan 	if (!(pev->point.function && !strncmp(pev->point.function, "0x", 2)))
3229da15bd9dSWang Nan 		return -EINVAL;
3230da15bd9dSWang Nan 	if (perf_probe_event_need_dwarf(pev))
3231da15bd9dSWang Nan 		return -EINVAL;
3232da15bd9dSWang Nan 
3233da15bd9dSWang Nan 	/*
3234da15bd9dSWang Nan 	 * This is 'perf probe /lib/libc.so 0xabcd'. Try to probe at
3235da15bd9dSWang Nan 	 * absolute address.
3236da15bd9dSWang Nan 	 *
3237da15bd9dSWang Nan 	 * Only one tev can be generated by this.
3238da15bd9dSWang Nan 	 */
3239da15bd9dSWang Nan 	*tevs = zalloc(sizeof(*tev));
3240da15bd9dSWang Nan 	if (!*tevs)
3241da15bd9dSWang Nan 		return -ENOMEM;
3242da15bd9dSWang Nan 
3243da15bd9dSWang Nan 	tev = *tevs;
3244da15bd9dSWang Nan 	tp = &tev->point;
3245da15bd9dSWang Nan 
3246da15bd9dSWang Nan 	/*
3247da15bd9dSWang Nan 	 * Don't use tp->offset, use address directly, because
3248da15bd9dSWang Nan 	 * in synthesize_probe_trace_command() address cannot be
3249da15bd9dSWang Nan 	 * zero.
3250da15bd9dSWang Nan 	 */
3251da15bd9dSWang Nan 	tp->address = pev->point.abs_address;
3252da15bd9dSWang Nan 	tp->retprobe = pp->retprobe;
3253da15bd9dSWang Nan 	tev->uprobes = pev->uprobes;
3254da15bd9dSWang Nan 
3255da15bd9dSWang Nan 	err = -ENOMEM;
3256da15bd9dSWang Nan 	/*
3257da15bd9dSWang Nan 	 * Give it a '0x' leading symbol name.
3258da15bd9dSWang Nan 	 * In __add_probe_trace_events, a NULL symbol is interpreted as
3259adba1634SIngo Molnar 	 * invalid.
3260da15bd9dSWang Nan 	 */
326122a66551SYang Jihong 	if (asprintf(&tp->symbol, "0x%" PRIx64, tp->address) < 0)
3262da15bd9dSWang Nan 		goto errout;
3263da15bd9dSWang Nan 
3264da15bd9dSWang Nan 	/* For kprobe, check range */
3265da15bd9dSWang Nan 	if ((!tev->uprobes) &&
3266da15bd9dSWang Nan 	    (kprobe_warn_out_range(tev->point.symbol,
3267da15bd9dSWang Nan 				   tev->point.address))) {
3268da15bd9dSWang Nan 		err = -EACCES;
3269da15bd9dSWang Nan 		goto errout;
3270da15bd9dSWang Nan 	}
3271da15bd9dSWang Nan 
327222a66551SYang Jihong 	if (asprintf(&tp->realname, "abs_%" PRIx64, tp->address) < 0)
3273da15bd9dSWang Nan 		goto errout;
3274da15bd9dSWang Nan 
3275da15bd9dSWang Nan 	if (pev->target) {
3276da15bd9dSWang Nan 		tp->module = strdup(pev->target);
3277da15bd9dSWang Nan 		if (!tp->module)
3278da15bd9dSWang Nan 			goto errout;
3279da15bd9dSWang Nan 	}
3280da15bd9dSWang Nan 
3281da15bd9dSWang Nan 	if (tev->group) {
3282da15bd9dSWang Nan 		tev->group = strdup(pev->group);
3283da15bd9dSWang Nan 		if (!tev->group)
3284da15bd9dSWang Nan 			goto errout;
3285da15bd9dSWang Nan 	}
3286da15bd9dSWang Nan 
3287da15bd9dSWang Nan 	if (pev->event) {
3288da15bd9dSWang Nan 		tev->event = strdup(pev->event);
3289da15bd9dSWang Nan 		if (!tev->event)
3290da15bd9dSWang Nan 			goto errout;
3291da15bd9dSWang Nan 	}
3292da15bd9dSWang Nan 
3293da15bd9dSWang Nan 	tev->nargs = pev->nargs;
3294da15bd9dSWang Nan 	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
3295d1d0e29cSMarkus Elfring 	if (!tev->args)
3296da15bd9dSWang Nan 		goto errout;
3297d1d0e29cSMarkus Elfring 
3298da15bd9dSWang Nan 	for (i = 0; i < tev->nargs; i++)
3299da15bd9dSWang Nan 		copy_to_probe_trace_arg(&tev->args[i], &pev->args[i]);
3300da15bd9dSWang Nan 
3301da15bd9dSWang Nan 	return 1;
3302da15bd9dSWang Nan 
3303da15bd9dSWang Nan errout:
3304da15bd9dSWang Nan 	clear_probe_trace_events(*tevs, 1);
3305da15bd9dSWang Nan 	*tevs = NULL;
3306da15bd9dSWang Nan 	return err;
3307da15bd9dSWang Nan }
3308da15bd9dSWang Nan 
33094d39c89fSIngo Molnar /* Concatenate two arrays */
331042bba263SMasami Hiramatsu static void *memcat(void *a, size_t sz_a, void *b, size_t sz_b)
331142bba263SMasami Hiramatsu {
331242bba263SMasami Hiramatsu 	void *ret;
331342bba263SMasami Hiramatsu 
331442bba263SMasami Hiramatsu 	ret = malloc(sz_a + sz_b);
331542bba263SMasami Hiramatsu 	if (ret) {
331642bba263SMasami Hiramatsu 		memcpy(ret, a, sz_a);
331742bba263SMasami Hiramatsu 		memcpy(ret + sz_a, b, sz_b);
331842bba263SMasami Hiramatsu 	}
331942bba263SMasami Hiramatsu 	return ret;
332042bba263SMasami Hiramatsu }
332142bba263SMasami Hiramatsu 
332242bba263SMasami Hiramatsu static int
332342bba263SMasami Hiramatsu concat_probe_trace_events(struct probe_trace_event **tevs, int *ntevs,
332442bba263SMasami Hiramatsu 			  struct probe_trace_event **tevs2, int ntevs2)
332542bba263SMasami Hiramatsu {
332642bba263SMasami Hiramatsu 	struct probe_trace_event *new_tevs;
332742bba263SMasami Hiramatsu 	int ret = 0;
332842bba263SMasami Hiramatsu 
3329f0a30dcaSRavi Bangoria 	if (*ntevs == 0) {
333042bba263SMasami Hiramatsu 		*tevs = *tevs2;
333142bba263SMasami Hiramatsu 		*ntevs = ntevs2;
333242bba263SMasami Hiramatsu 		*tevs2 = NULL;
333342bba263SMasami Hiramatsu 		return 0;
333442bba263SMasami Hiramatsu 	}
333542bba263SMasami Hiramatsu 
333642bba263SMasami Hiramatsu 	if (*ntevs + ntevs2 > probe_conf.max_probes)
333742bba263SMasami Hiramatsu 		ret = -E2BIG;
333842bba263SMasami Hiramatsu 	else {
33394d39c89fSIngo Molnar 		/* Concatenate the array of probe_trace_event */
334042bba263SMasami Hiramatsu 		new_tevs = memcat(*tevs, (*ntevs) * sizeof(**tevs),
334142bba263SMasami Hiramatsu 				  *tevs2, ntevs2 * sizeof(**tevs2));
334242bba263SMasami Hiramatsu 		if (!new_tevs)
334342bba263SMasami Hiramatsu 			ret = -ENOMEM;
334442bba263SMasami Hiramatsu 		else {
334542bba263SMasami Hiramatsu 			free(*tevs);
334642bba263SMasami Hiramatsu 			*tevs = new_tevs;
334742bba263SMasami Hiramatsu 			*ntevs += ntevs2;
334842bba263SMasami Hiramatsu 		}
334942bba263SMasami Hiramatsu 	}
335042bba263SMasami Hiramatsu 	if (ret < 0)
335142bba263SMasami Hiramatsu 		clear_probe_trace_events(*tevs2, ntevs2);
335242bba263SMasami Hiramatsu 	zfree(tevs2);
335342bba263SMasami Hiramatsu 
335442bba263SMasami Hiramatsu 	return ret;
335542bba263SMasami Hiramatsu }
335642bba263SMasami Hiramatsu 
335742bba263SMasami Hiramatsu /*
335842bba263SMasami Hiramatsu  * Try to find probe_trace_event from given probe caches. Return the number
335942bba263SMasami Hiramatsu  * of cached events found, if an error occurs return the error.
336042bba263SMasami Hiramatsu  */
336142bba263SMasami Hiramatsu static int find_cached_events(struct perf_probe_event *pev,
336242bba263SMasami Hiramatsu 			      struct probe_trace_event **tevs,
336342bba263SMasami Hiramatsu 			      const char *target)
336442bba263SMasami Hiramatsu {
336542bba263SMasami Hiramatsu 	struct probe_cache *cache;
336642bba263SMasami Hiramatsu 	struct probe_cache_entry *entry;
336742bba263SMasami Hiramatsu 	struct probe_trace_event *tmp_tevs = NULL;
336842bba263SMasami Hiramatsu 	int ntevs = 0;
336942bba263SMasami Hiramatsu 	int ret = 0;
337042bba263SMasami Hiramatsu 
3371f045b8c4SKrister Johansen 	cache = probe_cache__new(target, pev->nsi);
337242bba263SMasami Hiramatsu 	/* Return 0 ("not found") if the target has no probe cache. */
337342bba263SMasami Hiramatsu 	if (!cache)
337442bba263SMasami Hiramatsu 		return 0;
337542bba263SMasami Hiramatsu 
337642bba263SMasami Hiramatsu 	for_each_probe_cache_entry(entry, cache) {
337742bba263SMasami Hiramatsu 		/* Skip the cache entry which has no name */
337842bba263SMasami Hiramatsu 		if (!entry->pev.event || !entry->pev.group)
337942bba263SMasami Hiramatsu 			continue;
338042bba263SMasami Hiramatsu 		if ((!pev->group || strglobmatch(entry->pev.group, pev->group)) &&
338142bba263SMasami Hiramatsu 		    strglobmatch(entry->pev.event, pev->event)) {
338242bba263SMasami Hiramatsu 			ret = probe_cache_entry__get_event(entry, &tmp_tevs);
338342bba263SMasami Hiramatsu 			if (ret > 0)
338442bba263SMasami Hiramatsu 				ret = concat_probe_trace_events(tevs, &ntevs,
338542bba263SMasami Hiramatsu 								&tmp_tevs, ret);
338642bba263SMasami Hiramatsu 			if (ret < 0)
338742bba263SMasami Hiramatsu 				break;
338842bba263SMasami Hiramatsu 		}
338942bba263SMasami Hiramatsu 	}
339042bba263SMasami Hiramatsu 	probe_cache__delete(cache);
339142bba263SMasami Hiramatsu 	if (ret < 0) {
339242bba263SMasami Hiramatsu 		clear_probe_trace_events(*tevs, ntevs);
339342bba263SMasami Hiramatsu 		zfree(tevs);
339442bba263SMasami Hiramatsu 	} else {
339542bba263SMasami Hiramatsu 		ret = ntevs;
339642bba263SMasami Hiramatsu 		if (ntevs > 0 && target && target[0] == '/')
339742bba263SMasami Hiramatsu 			pev->uprobes = true;
339842bba263SMasami Hiramatsu 	}
339942bba263SMasami Hiramatsu 
340042bba263SMasami Hiramatsu 	return ret;
340142bba263SMasami Hiramatsu }
340242bba263SMasami Hiramatsu 
34031de7b8bfSMasami Hiramatsu /* Try to find probe_trace_event from all probe caches */
34041de7b8bfSMasami Hiramatsu static int find_cached_events_all(struct perf_probe_event *pev,
34051de7b8bfSMasami Hiramatsu 				   struct probe_trace_event **tevs)
34061de7b8bfSMasami Hiramatsu {
34071de7b8bfSMasami Hiramatsu 	struct probe_trace_event *tmp_tevs = NULL;
34081de7b8bfSMasami Hiramatsu 	struct strlist *bidlist;
34091de7b8bfSMasami Hiramatsu 	struct str_node *nd;
34101de7b8bfSMasami Hiramatsu 	char *pathname;
34111de7b8bfSMasami Hiramatsu 	int ntevs = 0;
34121de7b8bfSMasami Hiramatsu 	int ret;
34131de7b8bfSMasami Hiramatsu 
34141de7b8bfSMasami Hiramatsu 	/* Get the buildid list of all valid caches */
34151de7b8bfSMasami Hiramatsu 	bidlist = build_id_cache__list_all(true);
34161de7b8bfSMasami Hiramatsu 	if (!bidlist) {
34171de7b8bfSMasami Hiramatsu 		ret = -errno;
34181de7b8bfSMasami Hiramatsu 		pr_debug("Failed to get buildids: %d\n", ret);
34191de7b8bfSMasami Hiramatsu 		return ret;
34201de7b8bfSMasami Hiramatsu 	}
34211de7b8bfSMasami Hiramatsu 
34221de7b8bfSMasami Hiramatsu 	ret = 0;
34231de7b8bfSMasami Hiramatsu 	strlist__for_each_entry(nd, bidlist) {
34241de7b8bfSMasami Hiramatsu 		pathname = build_id_cache__origname(nd->s);
34251de7b8bfSMasami Hiramatsu 		ret = find_cached_events(pev, &tmp_tevs, pathname);
34261de7b8bfSMasami Hiramatsu 		/* In the case of cnt == 0, we just skip it */
34271de7b8bfSMasami Hiramatsu 		if (ret > 0)
34281de7b8bfSMasami Hiramatsu 			ret = concat_probe_trace_events(tevs, &ntevs,
34291de7b8bfSMasami Hiramatsu 							&tmp_tevs, ret);
34301de7b8bfSMasami Hiramatsu 		free(pathname);
34311de7b8bfSMasami Hiramatsu 		if (ret < 0)
34321de7b8bfSMasami Hiramatsu 			break;
34331de7b8bfSMasami Hiramatsu 	}
34341de7b8bfSMasami Hiramatsu 	strlist__delete(bidlist);
34351de7b8bfSMasami Hiramatsu 
34361de7b8bfSMasami Hiramatsu 	if (ret < 0) {
34371de7b8bfSMasami Hiramatsu 		clear_probe_trace_events(*tevs, ntevs);
34381de7b8bfSMasami Hiramatsu 		zfree(tevs);
34391de7b8bfSMasami Hiramatsu 	} else
34401de7b8bfSMasami Hiramatsu 		ret = ntevs;
34411de7b8bfSMasami Hiramatsu 
34421de7b8bfSMasami Hiramatsu 	return ret;
34431de7b8bfSMasami Hiramatsu }
34441de7b8bfSMasami Hiramatsu 
3445bc062230SMasami Hiramatsu static int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
3446bc062230SMasami Hiramatsu 					      struct probe_trace_event **tevs)
3447bc062230SMasami Hiramatsu {
3448bc062230SMasami Hiramatsu 	struct probe_cache *cache;
3449bc062230SMasami Hiramatsu 	struct probe_cache_entry *entry;
3450bc062230SMasami Hiramatsu 	struct probe_trace_event *tev;
3451bc062230SMasami Hiramatsu 	struct str_node *node;
3452bc062230SMasami Hiramatsu 	int ret, i;
3453bc062230SMasami Hiramatsu 
34541de7b8bfSMasami Hiramatsu 	if (pev->sdt) {
345542bba263SMasami Hiramatsu 		/* For SDT/cached events, we use special search functions */
34561de7b8bfSMasami Hiramatsu 		if (!pev->target)
34571de7b8bfSMasami Hiramatsu 			return find_cached_events_all(pev, tevs);
34581de7b8bfSMasami Hiramatsu 		else
345942bba263SMasami Hiramatsu 			return find_cached_events(pev, tevs, pev->target);
34601de7b8bfSMasami Hiramatsu 	}
3461f045b8c4SKrister Johansen 	cache = probe_cache__new(pev->target, pev->nsi);
3462bc062230SMasami Hiramatsu 	if (!cache)
3463bc062230SMasami Hiramatsu 		return 0;
3464bc062230SMasami Hiramatsu 
3465bc062230SMasami Hiramatsu 	entry = probe_cache__find(cache, pev);
3466bc062230SMasami Hiramatsu 	if (!entry) {
346736a009feSMasami Hiramatsu 		/* SDT must be in the cache */
346836a009feSMasami Hiramatsu 		ret = pev->sdt ? -ENOENT : 0;
3469bc062230SMasami Hiramatsu 		goto out;
3470bc062230SMasami Hiramatsu 	}
3471bc062230SMasami Hiramatsu 
3472bc062230SMasami Hiramatsu 	ret = strlist__nr_entries(entry->tevlist);
3473bc062230SMasami Hiramatsu 	if (ret > probe_conf.max_probes) {
3474bc062230SMasami Hiramatsu 		pr_debug("Too many entries matched in the cache of %s\n",
3475bc062230SMasami Hiramatsu 			 pev->target ? : "kernel");
3476bc062230SMasami Hiramatsu 		ret = -E2BIG;
3477bc062230SMasami Hiramatsu 		goto out;
3478bc062230SMasami Hiramatsu 	}
3479bc062230SMasami Hiramatsu 
3480bc062230SMasami Hiramatsu 	*tevs = zalloc(ret * sizeof(*tev));
3481bc062230SMasami Hiramatsu 	if (!*tevs) {
3482bc062230SMasami Hiramatsu 		ret = -ENOMEM;
3483bc062230SMasami Hiramatsu 		goto out;
3484bc062230SMasami Hiramatsu 	}
3485bc062230SMasami Hiramatsu 
3486bc062230SMasami Hiramatsu 	i = 0;
3487bc062230SMasami Hiramatsu 	strlist__for_each_entry(node, entry->tevlist) {
3488bc062230SMasami Hiramatsu 		tev = &(*tevs)[i++];
3489bc062230SMasami Hiramatsu 		ret = parse_probe_trace_command(node->s, tev);
3490bc062230SMasami Hiramatsu 		if (ret < 0)
3491bc062230SMasami Hiramatsu 			goto out;
3492bc062230SMasami Hiramatsu 		/* Set the uprobes attribute as same as original */
3493bc062230SMasami Hiramatsu 		tev->uprobes = pev->uprobes;
3494bc062230SMasami Hiramatsu 	}
3495bc062230SMasami Hiramatsu 	ret = i;
3496bc062230SMasami Hiramatsu 
3497bc062230SMasami Hiramatsu out:
3498bc062230SMasami Hiramatsu 	probe_cache__delete(cache);
3499bc062230SMasami Hiramatsu 	return ret;
3500bc062230SMasami Hiramatsu }
3501bc062230SMasami Hiramatsu 
35020e60836bSSrikar Dronamraju static int convert_to_probe_trace_events(struct perf_probe_event *pev,
3503ddb2f58fSMasami Hiramatsu 					 struct probe_trace_event **tevs)
3504e0faa8d3SMasami Hiramatsu {
3505eb948e50SMasami Hiramatsu 	int ret;
35064235b045SMasami Hiramatsu 
350736a009feSMasami Hiramatsu 	if (!pev->group && !pev->sdt) {
35082a12ec13SMasami Hiramatsu 		/* Set group name if not given */
35092a12ec13SMasami Hiramatsu 		if (!pev->uprobes) {
35102a12ec13SMasami Hiramatsu 			pev->group = strdup(PERFPROBE_GROUP);
35112a12ec13SMasami Hiramatsu 			ret = pev->group ? 0 : -ENOMEM;
35122a12ec13SMasami Hiramatsu 		} else
351344225521SMasami Hiramatsu 			ret = convert_exec_to_group(pev->target, &pev->group);
3514fb7345bbSMasami Hiramatsu 		if (ret != 0) {
3515fb7345bbSMasami Hiramatsu 			pr_warning("Failed to make a group name.\n");
3516fb7345bbSMasami Hiramatsu 			return ret;
3517fb7345bbSMasami Hiramatsu 		}
3518fb7345bbSMasami Hiramatsu 	}
3519fb7345bbSMasami Hiramatsu 
3520da15bd9dSWang Nan 	ret = try_to_find_absolute_address(pev, tevs);
3521da15bd9dSWang Nan 	if (ret > 0)
3522da15bd9dSWang Nan 		return ret;
3523da15bd9dSWang Nan 
3524bc062230SMasami Hiramatsu 	/* At first, we need to lookup cache entry */
3525bc062230SMasami Hiramatsu 	ret = find_probe_trace_events_from_cache(pev, tevs);
352636a009feSMasami Hiramatsu 	if (ret > 0 || pev->sdt)	/* SDT can be found only in the cache */
352736a009feSMasami Hiramatsu 		return ret == 0 ? -ENOENT : ret; /* Found in probe cache */
3528bc062230SMasami Hiramatsu 
35294b4da7f7SMasami Hiramatsu 	/* Convert perf_probe_event with debuginfo */
3530ddb2f58fSMasami Hiramatsu 	ret = try_to_find_probe_trace_events(pev, tevs);
3531e334016fSMasami Hiramatsu 	if (ret != 0)
3532190b57fcSMasami Hiramatsu 		return ret;	/* Found in debuginfo or got an error */
3533e0faa8d3SMasami Hiramatsu 
3534ddb2f58fSMasami Hiramatsu 	return find_probe_trace_events_from_map(pev, tevs);
35354235b045SMasami Hiramatsu }
35364235b045SMasami Hiramatsu 
353712fae5efSWang Nan int convert_perf_probe_events(struct perf_probe_event *pevs, int npevs)
35384235b045SMasami Hiramatsu {
3539844dffa5SNamhyung Kim 	int i, ret;
35404235b045SMasami Hiramatsu 
35414235b045SMasami Hiramatsu 	/* Loop 1: convert all events */
35424235b045SMasami Hiramatsu 	for (i = 0; i < npevs; i++) {
3543b031220dSMasami Hiramatsu 		/* Init kprobe blacklist if needed */
354412fae5efSWang Nan 		if (!pevs[i].uprobes)
3545b031220dSMasami Hiramatsu 			kprobe_blacklist__init();
35464235b045SMasami Hiramatsu 		/* Convert with or without debuginfo */
354712fae5efSWang Nan 		ret  = convert_to_probe_trace_events(&pevs[i], &pevs[i].tevs);
3548146a1439SMasami Hiramatsu 		if (ret < 0)
3549844dffa5SNamhyung Kim 			return ret;
355012fae5efSWang Nan 		pevs[i].ntevs = ret;
35514235b045SMasami Hiramatsu 	}
3552b031220dSMasami Hiramatsu 	/* This just release blacklist only if allocated */
3553b031220dSMasami Hiramatsu 	kprobe_blacklist__release();
35544235b045SMasami Hiramatsu 
3555844dffa5SNamhyung Kim 	return 0;
3556844dffa5SNamhyung Kim }
3557844dffa5SNamhyung Kim 
35581c20b1d1SMasami Hiramatsu static int show_probe_trace_event(struct probe_trace_event *tev)
35591c20b1d1SMasami Hiramatsu {
35601c20b1d1SMasami Hiramatsu 	char *buf = synthesize_probe_trace_command(tev);
35611c20b1d1SMasami Hiramatsu 
35621c20b1d1SMasami Hiramatsu 	if (!buf) {
35631c20b1d1SMasami Hiramatsu 		pr_debug("Failed to synthesize probe trace event.\n");
35641c20b1d1SMasami Hiramatsu 		return -EINVAL;
35651c20b1d1SMasami Hiramatsu 	}
35661c20b1d1SMasami Hiramatsu 
35671c20b1d1SMasami Hiramatsu 	/* Showing definition always go stdout */
35681c20b1d1SMasami Hiramatsu 	printf("%s\n", buf);
35691c20b1d1SMasami Hiramatsu 	free(buf);
35701c20b1d1SMasami Hiramatsu 
35711c20b1d1SMasami Hiramatsu 	return 0;
35721c20b1d1SMasami Hiramatsu }
35731c20b1d1SMasami Hiramatsu 
35741c20b1d1SMasami Hiramatsu int show_probe_trace_events(struct perf_probe_event *pevs, int npevs)
35751c20b1d1SMasami Hiramatsu {
35761c20b1d1SMasami Hiramatsu 	struct strlist *namelist = strlist__new(NULL, NULL);
35771c20b1d1SMasami Hiramatsu 	struct probe_trace_event *tev;
35781c20b1d1SMasami Hiramatsu 	struct perf_probe_event *pev;
35791c20b1d1SMasami Hiramatsu 	int i, j, ret = 0;
35801c20b1d1SMasami Hiramatsu 
35811c20b1d1SMasami Hiramatsu 	if (!namelist)
35821c20b1d1SMasami Hiramatsu 		return -ENOMEM;
35831c20b1d1SMasami Hiramatsu 
35841c20b1d1SMasami Hiramatsu 	for (j = 0; j < npevs && !ret; j++) {
35851c20b1d1SMasami Hiramatsu 		pev = &pevs[j];
35861c20b1d1SMasami Hiramatsu 		for (i = 0; i < pev->ntevs && !ret; i++) {
35871c20b1d1SMasami Hiramatsu 			tev = &pev->tevs[i];
35881c20b1d1SMasami Hiramatsu 			/* Skip if the symbol is out of .text or blacklisted */
35891c20b1d1SMasami Hiramatsu 			if (!tev->point.symbol && !pev->uprobes)
35901c20b1d1SMasami Hiramatsu 				continue;
35911c20b1d1SMasami Hiramatsu 
35921c20b1d1SMasami Hiramatsu 			/* Set new name for tev (and update namelist) */
35931c20b1d1SMasami Hiramatsu 			ret = probe_trace_event__set_name(tev, pev,
35941c20b1d1SMasami Hiramatsu 							  namelist, true);
35951c20b1d1SMasami Hiramatsu 			if (!ret)
35961c20b1d1SMasami Hiramatsu 				ret = show_probe_trace_event(tev);
35971c20b1d1SMasami Hiramatsu 		}
35981c20b1d1SMasami Hiramatsu 	}
35991c20b1d1SMasami Hiramatsu 	strlist__delete(namelist);
36001c20b1d1SMasami Hiramatsu 
36011c20b1d1SMasami Hiramatsu 	return ret;
36021c20b1d1SMasami Hiramatsu }
36031c20b1d1SMasami Hiramatsu 
360445237f98SMasami Hiramatsu static int show_bootconfig_event(struct probe_trace_event *tev)
360545237f98SMasami Hiramatsu {
360645237f98SMasami Hiramatsu 	struct probe_trace_point *tp = &tev->point;
360745237f98SMasami Hiramatsu 	struct strbuf buf;
360845237f98SMasami Hiramatsu 	char *ret = NULL;
360945237f98SMasami Hiramatsu 	int err;
361045237f98SMasami Hiramatsu 
361145237f98SMasami Hiramatsu 	if (strbuf_init(&buf, 32) < 0)
361245237f98SMasami Hiramatsu 		return -ENOMEM;
361345237f98SMasami Hiramatsu 
361445237f98SMasami Hiramatsu 	err = synthesize_kprobe_trace_def(tp, &buf);
361545237f98SMasami Hiramatsu 	if (err >= 0)
361645237f98SMasami Hiramatsu 		err = synthesize_probe_trace_args(tev, &buf);
361745237f98SMasami Hiramatsu 	if (err >= 0)
361845237f98SMasami Hiramatsu 		ret = strbuf_detach(&buf, NULL);
361945237f98SMasami Hiramatsu 	strbuf_release(&buf);
362045237f98SMasami Hiramatsu 
362145237f98SMasami Hiramatsu 	if (ret) {
362245237f98SMasami Hiramatsu 		printf("'%s'", ret);
362345237f98SMasami Hiramatsu 		free(ret);
362445237f98SMasami Hiramatsu 	}
362545237f98SMasami Hiramatsu 
362645237f98SMasami Hiramatsu 	return err;
362745237f98SMasami Hiramatsu }
362845237f98SMasami Hiramatsu 
362945237f98SMasami Hiramatsu int show_bootconfig_events(struct perf_probe_event *pevs, int npevs)
363045237f98SMasami Hiramatsu {
363145237f98SMasami Hiramatsu 	struct strlist *namelist = strlist__new(NULL, NULL);
363245237f98SMasami Hiramatsu 	struct probe_trace_event *tev;
363345237f98SMasami Hiramatsu 	struct perf_probe_event *pev;
363445237f98SMasami Hiramatsu 	char *cur_name = NULL;
363545237f98SMasami Hiramatsu 	int i, j, ret = 0;
363645237f98SMasami Hiramatsu 
363745237f98SMasami Hiramatsu 	if (!namelist)
363845237f98SMasami Hiramatsu 		return -ENOMEM;
363945237f98SMasami Hiramatsu 
364045237f98SMasami Hiramatsu 	for (j = 0; j < npevs && !ret; j++) {
364145237f98SMasami Hiramatsu 		pev = &pevs[j];
364245237f98SMasami Hiramatsu 		if (pev->group && strcmp(pev->group, "probe"))
364345237f98SMasami Hiramatsu 			pr_warning("WARN: Group name %s is ignored\n", pev->group);
364445237f98SMasami Hiramatsu 		if (pev->uprobes) {
364545237f98SMasami Hiramatsu 			pr_warning("ERROR: Bootconfig doesn't support uprobes\n");
364645237f98SMasami Hiramatsu 			ret = -EINVAL;
364745237f98SMasami Hiramatsu 			break;
364845237f98SMasami Hiramatsu 		}
364945237f98SMasami Hiramatsu 		for (i = 0; i < pev->ntevs && !ret; i++) {
365045237f98SMasami Hiramatsu 			tev = &pev->tevs[i];
365145237f98SMasami Hiramatsu 			/* Skip if the symbol is out of .text or blacklisted */
365245237f98SMasami Hiramatsu 			if (!tev->point.symbol && !pev->uprobes)
365345237f98SMasami Hiramatsu 				continue;
365445237f98SMasami Hiramatsu 
365545237f98SMasami Hiramatsu 			/* Set new name for tev (and update namelist) */
365645237f98SMasami Hiramatsu 			ret = probe_trace_event__set_name(tev, pev,
365745237f98SMasami Hiramatsu 							  namelist, true);
365845237f98SMasami Hiramatsu 			if (ret)
365945237f98SMasami Hiramatsu 				break;
366045237f98SMasami Hiramatsu 
366145237f98SMasami Hiramatsu 			if (!cur_name || strcmp(cur_name, tev->event)) {
366245237f98SMasami Hiramatsu 				printf("%sftrace.event.kprobes.%s.probe = ",
366345237f98SMasami Hiramatsu 					cur_name ? "\n" : "", tev->event);
366445237f98SMasami Hiramatsu 				cur_name = tev->event;
366545237f98SMasami Hiramatsu 			} else
366645237f98SMasami Hiramatsu 				printf(", ");
366745237f98SMasami Hiramatsu 			ret = show_bootconfig_event(tev);
366845237f98SMasami Hiramatsu 		}
366945237f98SMasami Hiramatsu 	}
367045237f98SMasami Hiramatsu 	printf("\n");
367145237f98SMasami Hiramatsu 	strlist__delete(namelist);
367245237f98SMasami Hiramatsu 
367345237f98SMasami Hiramatsu 	return ret;
367445237f98SMasami Hiramatsu }
367545237f98SMasami Hiramatsu 
367612fae5efSWang Nan int apply_perf_probe_events(struct perf_probe_event *pevs, int npevs)
3677844dffa5SNamhyung Kim {
3678844dffa5SNamhyung Kim 	int i, ret = 0;
3679844dffa5SNamhyung Kim 
36804235b045SMasami Hiramatsu 	/* Loop 2: add all events */
36818635bf6eSArnaldo Carvalho de Melo 	for (i = 0; i < npevs; i++) {
368212fae5efSWang Nan 		ret = __add_probe_trace_events(&pevs[i], pevs[i].tevs,
368312fae5efSWang Nan 					       pevs[i].ntevs,
3684ddb2f58fSMasami Hiramatsu 					       probe_conf.force_add);
3685fbee632dSArnaldo Carvalho de Melo 		if (ret < 0)
3686fbee632dSArnaldo Carvalho de Melo 			break;
3687fbee632dSArnaldo Carvalho de Melo 	}
3688844dffa5SNamhyung Kim 	return ret;
3689844dffa5SNamhyung Kim }
3690844dffa5SNamhyung Kim 
369112fae5efSWang Nan void cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs)
3692844dffa5SNamhyung Kim {
3693844dffa5SNamhyung Kim 	int i, j;
3694544abd44SKrister Johansen 	struct perf_probe_event *pev;
3695844dffa5SNamhyung Kim 
3696449e5b24SMasami Hiramatsu 	/* Loop 3: cleanup and free trace events  */
3697449e5b24SMasami Hiramatsu 	for (i = 0; i < npevs; i++) {
3698544abd44SKrister Johansen 		pev = &pevs[i];
369912fae5efSWang Nan 		for (j = 0; j < pevs[i].ntevs; j++)
370012fae5efSWang Nan 			clear_probe_trace_event(&pevs[i].tevs[j]);
370112fae5efSWang Nan 		zfree(&pevs[i].tevs);
370212fae5efSWang Nan 		pevs[i].ntevs = 0;
3703544abd44SKrister Johansen 		nsinfo__zput(pev->nsi);
3704a43aac29SNamhyung Kim 		clear_perf_probe_event(&pevs[i]);
3705449e5b24SMasami Hiramatsu 	}
3706844dffa5SNamhyung Kim }
3707844dffa5SNamhyung Kim 
3708844dffa5SNamhyung Kim int add_perf_probe_events(struct perf_probe_event *pevs, int npevs)
3709844dffa5SNamhyung Kim {
3710844dffa5SNamhyung Kim 	int ret;
3711844dffa5SNamhyung Kim 
37129bae1e8cSNamhyung Kim 	ret = init_probe_symbol_maps(pevs->uprobes);
37139bae1e8cSNamhyung Kim 	if (ret < 0)
37149bae1e8cSNamhyung Kim 		return ret;
37159bae1e8cSNamhyung Kim 
371612fae5efSWang Nan 	ret = convert_perf_probe_events(pevs, npevs);
3717844dffa5SNamhyung Kim 	if (ret == 0)
371812fae5efSWang Nan 		ret = apply_perf_probe_events(pevs, npevs);
3719844dffa5SNamhyung Kim 
372012fae5efSWang Nan 	cleanup_perf_probe_events(pevs, npevs);
3721146a1439SMasami Hiramatsu 
37229bae1e8cSNamhyung Kim 	exit_probe_symbol_maps();
3723146a1439SMasami Hiramatsu 	return ret;
3724e0faa8d3SMasami Hiramatsu }
3725e0faa8d3SMasami Hiramatsu 
3726307a464bSMasami Hiramatsu int del_perf_probe_events(struct strfilter *filter)
3727fa28244dSMasami Hiramatsu {
3728307a464bSMasami Hiramatsu 	int ret, ret2, ufd = -1, kfd = -1;
3729307a464bSMasami Hiramatsu 	char *str = strfilter__string(filter);
3730307a464bSMasami Hiramatsu 
3731307a464bSMasami Hiramatsu 	if (!str)
3732307a464bSMasami Hiramatsu 		return -EINVAL;
3733307a464bSMasami Hiramatsu 
3734fa28244dSMasami Hiramatsu 	/* Get current event names */
373592f6c72eSMasami Hiramatsu 	ret = probe_file__open_both(&kfd, &ufd, PF_FL_RW);
373692f6c72eSMasami Hiramatsu 	if (ret < 0)
373792f6c72eSMasami Hiramatsu 		goto out;
3738225466f1SSrikar Dronamraju 
373992f6c72eSMasami Hiramatsu 	ret = probe_file__del_events(kfd, filter);
3740307a464bSMasami Hiramatsu 	if (ret < 0 && ret != -ENOENT)
3741225466f1SSrikar Dronamraju 		goto error;
3742fa28244dSMasami Hiramatsu 
374392f6c72eSMasami Hiramatsu 	ret2 = probe_file__del_events(ufd, filter);
3744dddc7ee3SMasami Hiramatsu 	if (ret2 < 0 && ret2 != -ENOENT) {
37456dbe31f7SMasami Hiramatsu 		ret = ret2;
3746dddc7ee3SMasami Hiramatsu 		goto error;
3747dddc7ee3SMasami Hiramatsu 	}
3748307a464bSMasami Hiramatsu 	ret = 0;
3749225466f1SSrikar Dronamraju 
3750225466f1SSrikar Dronamraju error:
375192f6c72eSMasami Hiramatsu 	if (kfd >= 0)
3752225466f1SSrikar Dronamraju 		close(kfd);
375392f6c72eSMasami Hiramatsu 	if (ufd >= 0)
3754225466f1SSrikar Dronamraju 		close(ufd);
375592f6c72eSMasami Hiramatsu out:
3756307a464bSMasami Hiramatsu 	free(str);
3757146a1439SMasami Hiramatsu 
3758146a1439SMasami Hiramatsu 	return ret;
3759fa28244dSMasami Hiramatsu }
3760225466f1SSrikar Dronamraju 
3761544abd44SKrister Johansen int show_available_funcs(const char *target, struct nsinfo *nsi,
3762544abd44SKrister Johansen 			 struct strfilter *_filter, bool user)
3763e80711caSMasami Hiramatsu {
37642df58634SMasami Hiramatsu 	struct map *map;
376563df0e4bSIan Rogers 	struct dso *dso;
37662df58634SMasami Hiramatsu 	int ret;
37672df58634SMasami Hiramatsu 
37689bae1e8cSNamhyung Kim 	ret = init_probe_symbol_maps(user);
37692df58634SMasami Hiramatsu 	if (ret < 0)
37702df58634SMasami Hiramatsu 		return ret;
37712df58634SMasami Hiramatsu 
37722df58634SMasami Hiramatsu 	/* Get a symbol map */
3773544abd44SKrister Johansen 	map = get_target_map(target, nsi, user);
37742df58634SMasami Hiramatsu 	if (!map) {
37752df58634SMasami Hiramatsu 		pr_err("Failed to get a map for %s\n", (target) ? : "kernel");
3776e80711caSMasami Hiramatsu 		return -EINVAL;
3777e80711caSMasami Hiramatsu 	}
37782df58634SMasami Hiramatsu 
3779be39db9fSArnaldo Carvalho de Melo 	ret = map__load(map);
3780e7049342SMasami Hiramatsu 	if (ret) {
3781e7049342SMasami Hiramatsu 		if (ret == -2) {
3782e7049342SMasami Hiramatsu 			char *str = strfilter__string(_filter);
3783e7049342SMasami Hiramatsu 			pr_err("Failed to find symbols matched to \"%s\"\n",
3784e7049342SMasami Hiramatsu 			       str);
3785e7049342SMasami Hiramatsu 			free(str);
3786e7049342SMasami Hiramatsu 		} else
3787e7049342SMasami Hiramatsu 			pr_err("Failed to load symbols in %s\n",
3788e7049342SMasami Hiramatsu 			       (target) ? : "kernel");
37892df58634SMasami Hiramatsu 		goto end;
37902df58634SMasami Hiramatsu 	}
379163df0e4bSIan Rogers 	dso = map__dso(map);
379263df0e4bSIan Rogers 	dso__sort_by_name(dso);
3793e80711caSMasami Hiramatsu 
37942df58634SMasami Hiramatsu 	/* Show all (filtered) symbols */
37952df58634SMasami Hiramatsu 	setup_pager();
3796fd227598SArnaldo Carvalho de Melo 
3797*ee756ef7SIan Rogers 	for (size_t i = 0; i < dso__symbol_names_len(dso); i++) {
3798*ee756ef7SIan Rogers 		struct symbol *pos = dso__symbol_names(dso)[i];
3799fd227598SArnaldo Carvalho de Melo 
3800259dce91SIan Rogers 		if (strfilter__compare(_filter, pos->name))
3801259dce91SIan Rogers 			printf("%s\n", pos->name);
3802fd227598SArnaldo Carvalho de Melo 	}
38032df58634SMasami Hiramatsu end:
380484c2cafaSArnaldo Carvalho de Melo 	map__put(map);
38059bae1e8cSNamhyung Kim 	exit_probe_symbol_maps();
3806225466f1SSrikar Dronamraju 
38072df58634SMasami Hiramatsu 	return ret;
3808225466f1SSrikar Dronamraju }
3809225466f1SSrikar Dronamraju 
3810da15bd9dSWang Nan int copy_to_probe_trace_arg(struct probe_trace_arg *tvar,
3811da15bd9dSWang Nan 			    struct perf_probe_arg *pvar)
3812da15bd9dSWang Nan {
3813da15bd9dSWang Nan 	tvar->value = strdup(pvar->var);
3814da15bd9dSWang Nan 	if (tvar->value == NULL)
3815da15bd9dSWang Nan 		return -ENOMEM;
3816da15bd9dSWang Nan 	if (pvar->type) {
3817da15bd9dSWang Nan 		tvar->type = strdup(pvar->type);
3818da15bd9dSWang Nan 		if (tvar->type == NULL)
3819da15bd9dSWang Nan 			return -ENOMEM;
3820da15bd9dSWang Nan 	}
3821da15bd9dSWang Nan 	if (pvar->name) {
3822da15bd9dSWang Nan 		tvar->name = strdup(pvar->name);
3823da15bd9dSWang Nan 		if (tvar->name == NULL)
3824da15bd9dSWang Nan 			return -ENOMEM;
3825da15bd9dSWang Nan 	} else
3826da15bd9dSWang Nan 		tvar->name = NULL;
3827da15bd9dSWang Nan 	return 0;
3828da15bd9dSWang Nan }
3829