162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * probe-event.c : perf-probe definition to probe_events format converter
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Written by Masami Hiramatsu <mhiramat@redhat.com>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <inttypes.h>
962306a36Sopenharmony_ci#include <sys/utsname.h>
1062306a36Sopenharmony_ci#include <sys/types.h>
1162306a36Sopenharmony_ci#include <sys/stat.h>
1262306a36Sopenharmony_ci#include <fcntl.h>
1362306a36Sopenharmony_ci#include <errno.h>
1462306a36Sopenharmony_ci#include <stdio.h>
1562306a36Sopenharmony_ci#include <unistd.h>
1662306a36Sopenharmony_ci#include <stdlib.h>
1762306a36Sopenharmony_ci#include <string.h>
1862306a36Sopenharmony_ci#include <stdarg.h>
1962306a36Sopenharmony_ci#include <limits.h>
2062306a36Sopenharmony_ci#include <elf.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "build-id.h"
2362306a36Sopenharmony_ci#include "event.h"
2462306a36Sopenharmony_ci#include "namespaces.h"
2562306a36Sopenharmony_ci#include "strlist.h"
2662306a36Sopenharmony_ci#include "strfilter.h"
2762306a36Sopenharmony_ci#include "debug.h"
2862306a36Sopenharmony_ci#include "dso.h"
2962306a36Sopenharmony_ci#include "color.h"
3062306a36Sopenharmony_ci#include "map.h"
3162306a36Sopenharmony_ci#include "maps.h"
3262306a36Sopenharmony_ci#include "mutex.h"
3362306a36Sopenharmony_ci#include "symbol.h"
3462306a36Sopenharmony_ci#include <api/fs/fs.h>
3562306a36Sopenharmony_ci#include "trace-event.h"	/* For __maybe_unused */
3662306a36Sopenharmony_ci#include "probe-event.h"
3762306a36Sopenharmony_ci#include "probe-finder.h"
3862306a36Sopenharmony_ci#include "probe-file.h"
3962306a36Sopenharmony_ci#include "session.h"
4062306a36Sopenharmony_ci#include "string2.h"
4162306a36Sopenharmony_ci#include "strbuf.h"
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#include <subcmd/pager.h>
4462306a36Sopenharmony_ci#include <linux/ctype.h>
4562306a36Sopenharmony_ci#include <linux/zalloc.h>
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#ifdef HAVE_DEBUGINFOD_SUPPORT
4862306a36Sopenharmony_ci#include <elfutils/debuginfod.h>
4962306a36Sopenharmony_ci#endif
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define PERFPROBE_GROUP "probe"
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cibool probe_event_dry_run;	/* Dry run flag */
5462306a36Sopenharmony_cistruct probe_conf probe_conf = { .magic_num = DEFAULT_PROBE_MAGIC_NUM };
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic char *synthesize_perf_probe_point(struct perf_probe_point *pp);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define semantic_error(msg ...) pr_err("Semantic error :" msg)
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ciint e_snprintf(char *str, size_t size, const char *format, ...)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	int ret;
6362306a36Sopenharmony_ci	va_list ap;
6462306a36Sopenharmony_ci	va_start(ap, format);
6562306a36Sopenharmony_ci	ret = vsnprintf(str, size, format, ap);
6662306a36Sopenharmony_ci	va_end(ap);
6762306a36Sopenharmony_ci	if (ret >= (int)size)
6862306a36Sopenharmony_ci		ret = -E2BIG;
6962306a36Sopenharmony_ci	return ret;
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic struct machine *host_machine;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci/* Initialize symbol maps and path of vmlinux/modules */
7562306a36Sopenharmony_ciint init_probe_symbol_maps(bool user_only)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	int ret;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	symbol_conf.allow_aliases = true;
8062306a36Sopenharmony_ci	ret = symbol__init(NULL);
8162306a36Sopenharmony_ci	if (ret < 0) {
8262306a36Sopenharmony_ci		pr_debug("Failed to init symbol map.\n");
8362306a36Sopenharmony_ci		goto out;
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	if (host_machine || user_only)	/* already initialized */
8762306a36Sopenharmony_ci		return 0;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (symbol_conf.vmlinux_name)
9062306a36Sopenharmony_ci		pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	host_machine = machine__new_host();
9362306a36Sopenharmony_ci	if (!host_machine) {
9462306a36Sopenharmony_ci		pr_debug("machine__new_host() failed.\n");
9562306a36Sopenharmony_ci		symbol__exit();
9662306a36Sopenharmony_ci		ret = -1;
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ciout:
9962306a36Sopenharmony_ci	if (ret < 0)
10062306a36Sopenharmony_ci		pr_warning("Failed to init vmlinux path.\n");
10162306a36Sopenharmony_ci	return ret;
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_civoid exit_probe_symbol_maps(void)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	machine__delete(host_machine);
10762306a36Sopenharmony_ci	host_machine = NULL;
10862306a36Sopenharmony_ci	symbol__exit();
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic struct ref_reloc_sym *kernel_get_ref_reloc_sym(struct map **pmap)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	struct kmap *kmap;
11462306a36Sopenharmony_ci	struct map *map = machine__kernel_map(host_machine);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (map__load(map) < 0)
11762306a36Sopenharmony_ci		return NULL;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	kmap = map__kmap(map);
12062306a36Sopenharmony_ci	if (!kmap)
12162306a36Sopenharmony_ci		return NULL;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	if (pmap)
12462306a36Sopenharmony_ci		*pmap = map;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	return kmap->ref_reloc_sym;
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic int kernel_get_symbol_address_by_name(const char *name, u64 *addr,
13062306a36Sopenharmony_ci					     bool reloc, bool reladdr)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	struct ref_reloc_sym *reloc_sym;
13362306a36Sopenharmony_ci	struct symbol *sym;
13462306a36Sopenharmony_ci	struct map *map;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	/* ref_reloc_sym is just a label. Need a special fix*/
13762306a36Sopenharmony_ci	reloc_sym = kernel_get_ref_reloc_sym(&map);
13862306a36Sopenharmony_ci	if (reloc_sym && strcmp(name, reloc_sym->name) == 0)
13962306a36Sopenharmony_ci		*addr = (!map__reloc(map) || reloc) ? reloc_sym->addr :
14062306a36Sopenharmony_ci			reloc_sym->unrelocated_addr;
14162306a36Sopenharmony_ci	else {
14262306a36Sopenharmony_ci		sym = machine__find_kernel_symbol_by_name(host_machine, name, &map);
14362306a36Sopenharmony_ci		if (!sym)
14462306a36Sopenharmony_ci			return -ENOENT;
14562306a36Sopenharmony_ci		*addr = map__unmap_ip(map, sym->start) -
14662306a36Sopenharmony_ci			((reloc) ? 0 : map__reloc(map)) -
14762306a36Sopenharmony_ci			((reladdr) ? map__start(map) : 0);
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci	return 0;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic struct map *kernel_get_module_map(const char *module)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	struct maps *maps = machine__kernel_maps(host_machine);
15562306a36Sopenharmony_ci	struct map_rb_node *pos;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	/* A file path -- this is an offline module */
15862306a36Sopenharmony_ci	if (module && strchr(module, '/'))
15962306a36Sopenharmony_ci		return dso__new_map(module);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (!module) {
16262306a36Sopenharmony_ci		struct map *map = machine__kernel_map(host_machine);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		return map__get(map);
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	maps__for_each_entry(maps, pos) {
16862306a36Sopenharmony_ci		/* short_name is "[module]" */
16962306a36Sopenharmony_ci		struct dso *dso = map__dso(pos->map);
17062306a36Sopenharmony_ci		const char *short_name = dso->short_name;
17162306a36Sopenharmony_ci		u16 short_name_len =  dso->short_name_len;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci		if (strncmp(short_name + 1, module,
17462306a36Sopenharmony_ci			    short_name_len - 2) == 0 &&
17562306a36Sopenharmony_ci		    module[short_name_len - 2] == '\0') {
17662306a36Sopenharmony_ci			return map__get(pos->map);
17762306a36Sopenharmony_ci		}
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci	return NULL;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_cistruct map *get_target_map(const char *target, struct nsinfo *nsi, bool user)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	/* Init maps of given executable or kernel */
18562306a36Sopenharmony_ci	if (user) {
18662306a36Sopenharmony_ci		struct map *map;
18762306a36Sopenharmony_ci		struct dso *dso;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci		map = dso__new_map(target);
19062306a36Sopenharmony_ci		dso = map ? map__dso(map) : NULL;
19162306a36Sopenharmony_ci		if (dso) {
19262306a36Sopenharmony_ci			mutex_lock(&dso->lock);
19362306a36Sopenharmony_ci			nsinfo__put(dso->nsinfo);
19462306a36Sopenharmony_ci			dso->nsinfo = nsinfo__get(nsi);
19562306a36Sopenharmony_ci			mutex_unlock(&dso->lock);
19662306a36Sopenharmony_ci		}
19762306a36Sopenharmony_ci		return map;
19862306a36Sopenharmony_ci	} else {
19962306a36Sopenharmony_ci		return kernel_get_module_map(target);
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic int convert_exec_to_group(const char *exec, char **result)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	char *ptr1, *ptr2, *exec_copy;
20662306a36Sopenharmony_ci	char buf[64];
20762306a36Sopenharmony_ci	int ret;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	exec_copy = strdup(exec);
21062306a36Sopenharmony_ci	if (!exec_copy)
21162306a36Sopenharmony_ci		return -ENOMEM;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	ptr1 = basename(exec_copy);
21462306a36Sopenharmony_ci	if (!ptr1) {
21562306a36Sopenharmony_ci		ret = -EINVAL;
21662306a36Sopenharmony_ci		goto out;
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	for (ptr2 = ptr1; *ptr2 != '\0'; ptr2++) {
22062306a36Sopenharmony_ci		if (!isalnum(*ptr2) && *ptr2 != '_') {
22162306a36Sopenharmony_ci			*ptr2 = '\0';
22262306a36Sopenharmony_ci			break;
22362306a36Sopenharmony_ci		}
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1);
22762306a36Sopenharmony_ci	if (ret < 0)
22862306a36Sopenharmony_ci		goto out;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	*result = strdup(buf);
23162306a36Sopenharmony_ci	ret = *result ? 0 : -ENOMEM;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ciout:
23462306a36Sopenharmony_ci	free(exec_copy);
23562306a36Sopenharmony_ci	return ret;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic void clear_perf_probe_point(struct perf_probe_point *pp)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	zfree(&pp->file);
24162306a36Sopenharmony_ci	zfree(&pp->function);
24262306a36Sopenharmony_ci	zfree(&pp->lazy_line);
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	int i;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	for (i = 0; i < ntevs; i++)
25062306a36Sopenharmony_ci		clear_probe_trace_event(tevs + i);
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic bool kprobe_blacklist__listed(u64 address);
25462306a36Sopenharmony_cistatic bool kprobe_warn_out_range(const char *symbol, u64 address)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct map *map;
25762306a36Sopenharmony_ci	bool ret = false;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	map = kernel_get_module_map(NULL);
26062306a36Sopenharmony_ci	if (map) {
26162306a36Sopenharmony_ci		ret = address <= map__start(map) || map__end(map) < address;
26262306a36Sopenharmony_ci		if (ret)
26362306a36Sopenharmony_ci			pr_warning("%s is out of .text, skip it.\n", symbol);
26462306a36Sopenharmony_ci		map__put(map);
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci	if (!ret && kprobe_blacklist__listed(address)) {
26762306a36Sopenharmony_ci		pr_warning("%s is blacklisted function, skip it.\n", symbol);
26862306a36Sopenharmony_ci		ret = true;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	return ret;
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci/*
27562306a36Sopenharmony_ci * @module can be module name of module file path. In case of path,
27662306a36Sopenharmony_ci * inspect elf and find out what is actual module name.
27762306a36Sopenharmony_ci * Caller has to free mod_name after using it.
27862306a36Sopenharmony_ci */
27962306a36Sopenharmony_cistatic char *find_module_name(const char *module)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	int fd;
28262306a36Sopenharmony_ci	Elf *elf;
28362306a36Sopenharmony_ci	GElf_Ehdr ehdr;
28462306a36Sopenharmony_ci	GElf_Shdr shdr;
28562306a36Sopenharmony_ci	Elf_Data *data;
28662306a36Sopenharmony_ci	Elf_Scn *sec;
28762306a36Sopenharmony_ci	char *mod_name = NULL;
28862306a36Sopenharmony_ci	int name_offset;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	fd = open(module, O_RDONLY);
29162306a36Sopenharmony_ci	if (fd < 0)
29262306a36Sopenharmony_ci		return NULL;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
29562306a36Sopenharmony_ci	if (elf == NULL)
29662306a36Sopenharmony_ci		goto elf_err;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	if (gelf_getehdr(elf, &ehdr) == NULL)
29962306a36Sopenharmony_ci		goto ret_err;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	sec = elf_section_by_name(elf, &ehdr, &shdr,
30262306a36Sopenharmony_ci			".gnu.linkonce.this_module", NULL);
30362306a36Sopenharmony_ci	if (!sec)
30462306a36Sopenharmony_ci		goto ret_err;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	data = elf_getdata(sec, NULL);
30762306a36Sopenharmony_ci	if (!data || !data->d_buf)
30862306a36Sopenharmony_ci		goto ret_err;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/*
31162306a36Sopenharmony_ci	 * NOTE:
31262306a36Sopenharmony_ci	 * '.gnu.linkonce.this_module' section of kernel module elf directly
31362306a36Sopenharmony_ci	 * maps to 'struct module' from linux/module.h. This section contains
31462306a36Sopenharmony_ci	 * actual module name which will be used by kernel after loading it.
31562306a36Sopenharmony_ci	 * But, we cannot use 'struct module' here since linux/module.h is not
31662306a36Sopenharmony_ci	 * exposed to user-space. Offset of 'name' has remained same from long
31762306a36Sopenharmony_ci	 * time, so hardcoding it here.
31862306a36Sopenharmony_ci	 */
31962306a36Sopenharmony_ci	if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
32062306a36Sopenharmony_ci		name_offset = 12;
32162306a36Sopenharmony_ci	else	/* expect ELFCLASS64 by default */
32262306a36Sopenharmony_ci		name_offset = 24;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	mod_name = strdup((char *)data->d_buf + name_offset);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ciret_err:
32762306a36Sopenharmony_ci	elf_end(elf);
32862306a36Sopenharmony_cielf_err:
32962306a36Sopenharmony_ci	close(fd);
33062306a36Sopenharmony_ci	return mod_name;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci#ifdef HAVE_DWARF_SUPPORT
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic int kernel_get_module_dso(const char *module, struct dso **pdso)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	struct dso *dso;
33862306a36Sopenharmony_ci	struct map *map;
33962306a36Sopenharmony_ci	const char *vmlinux_name;
34062306a36Sopenharmony_ci	int ret = 0;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	if (module) {
34362306a36Sopenharmony_ci		char module_name[128];
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci		snprintf(module_name, sizeof(module_name), "[%s]", module);
34662306a36Sopenharmony_ci		map = maps__find_by_name(machine__kernel_maps(host_machine), module_name);
34762306a36Sopenharmony_ci		if (map) {
34862306a36Sopenharmony_ci			dso = map__dso(map);
34962306a36Sopenharmony_ci			goto found;
35062306a36Sopenharmony_ci		}
35162306a36Sopenharmony_ci		pr_debug("Failed to find module %s.\n", module);
35262306a36Sopenharmony_ci		return -ENOENT;
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	map = machine__kernel_map(host_machine);
35662306a36Sopenharmony_ci	dso = map__dso(map);
35762306a36Sopenharmony_ci	if (!dso->has_build_id)
35862306a36Sopenharmony_ci		dso__read_running_kernel_build_id(dso, host_machine);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	vmlinux_name = symbol_conf.vmlinux_name;
36162306a36Sopenharmony_ci	dso->load_errno = 0;
36262306a36Sopenharmony_ci	if (vmlinux_name)
36362306a36Sopenharmony_ci		ret = dso__load_vmlinux(dso, map, vmlinux_name, false);
36462306a36Sopenharmony_ci	else
36562306a36Sopenharmony_ci		ret = dso__load_vmlinux_path(dso, map);
36662306a36Sopenharmony_cifound:
36762306a36Sopenharmony_ci	*pdso = dso;
36862306a36Sopenharmony_ci	return ret;
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci/*
37262306a36Sopenharmony_ci * Some binaries like glibc have special symbols which are on the symbol
37362306a36Sopenharmony_ci * table, but not in the debuginfo. If we can find the address of the
37462306a36Sopenharmony_ci * symbol from map, we can translate the address back to the probe point.
37562306a36Sopenharmony_ci */
37662306a36Sopenharmony_cistatic int find_alternative_probe_point(struct debuginfo *dinfo,
37762306a36Sopenharmony_ci					struct perf_probe_point *pp,
37862306a36Sopenharmony_ci					struct perf_probe_point *result,
37962306a36Sopenharmony_ci					const char *target, struct nsinfo *nsi,
38062306a36Sopenharmony_ci					bool uprobes)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	struct map *map = NULL;
38362306a36Sopenharmony_ci	struct symbol *sym;
38462306a36Sopenharmony_ci	u64 address = 0;
38562306a36Sopenharmony_ci	int ret = -ENOENT;
38662306a36Sopenharmony_ci	size_t idx;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	/* This can work only for function-name based one */
38962306a36Sopenharmony_ci	if (!pp->function || pp->file)
39062306a36Sopenharmony_ci		return -ENOTSUP;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	map = get_target_map(target, nsi, uprobes);
39362306a36Sopenharmony_ci	if (!map)
39462306a36Sopenharmony_ci		return -EINVAL;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* Find the address of given function */
39762306a36Sopenharmony_ci	map__for_each_symbol_by_name(map, pp->function, sym, idx) {
39862306a36Sopenharmony_ci		if (uprobes) {
39962306a36Sopenharmony_ci			address = sym->start;
40062306a36Sopenharmony_ci			if (sym->type == STT_GNU_IFUNC)
40162306a36Sopenharmony_ci				pr_warning("Warning: The probe function (%s) is a GNU indirect function.\n"
40262306a36Sopenharmony_ci					   "Consider identifying the final function used at run time and set the probe directly on that.\n",
40362306a36Sopenharmony_ci					   pp->function);
40462306a36Sopenharmony_ci		} else
40562306a36Sopenharmony_ci			address = map__unmap_ip(map, sym->start) - map__reloc(map);
40662306a36Sopenharmony_ci		break;
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci	if (!address) {
40962306a36Sopenharmony_ci		ret = -ENOENT;
41062306a36Sopenharmony_ci		goto out;
41162306a36Sopenharmony_ci	}
41262306a36Sopenharmony_ci	pr_debug("Symbol %s address found : %" PRIx64 "\n",
41362306a36Sopenharmony_ci			pp->function, address);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	ret = debuginfo__find_probe_point(dinfo, address, result);
41662306a36Sopenharmony_ci	if (ret <= 0)
41762306a36Sopenharmony_ci		ret = (!ret) ? -ENOENT : ret;
41862306a36Sopenharmony_ci	else {
41962306a36Sopenharmony_ci		result->offset += pp->offset;
42062306a36Sopenharmony_ci		result->line += pp->line;
42162306a36Sopenharmony_ci		result->retprobe = pp->retprobe;
42262306a36Sopenharmony_ci		ret = 0;
42362306a36Sopenharmony_ci	}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ciout:
42662306a36Sopenharmony_ci	map__put(map);
42762306a36Sopenharmony_ci	return ret;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic int get_alternative_probe_event(struct debuginfo *dinfo,
43262306a36Sopenharmony_ci				       struct perf_probe_event *pev,
43362306a36Sopenharmony_ci				       struct perf_probe_point *tmp)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	int ret;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	memcpy(tmp, &pev->point, sizeof(*tmp));
43862306a36Sopenharmony_ci	memset(&pev->point, 0, sizeof(pev->point));
43962306a36Sopenharmony_ci	ret = find_alternative_probe_point(dinfo, tmp, &pev->point, pev->target,
44062306a36Sopenharmony_ci					   pev->nsi, pev->uprobes);
44162306a36Sopenharmony_ci	if (ret < 0)
44262306a36Sopenharmony_ci		memcpy(&pev->point, tmp, sizeof(*tmp));
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	return ret;
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic int get_alternative_line_range(struct debuginfo *dinfo,
44862306a36Sopenharmony_ci				      struct line_range *lr,
44962306a36Sopenharmony_ci				      const char *target, bool user)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct perf_probe_point pp = { .function = lr->function,
45262306a36Sopenharmony_ci				       .file = lr->file,
45362306a36Sopenharmony_ci				       .line = lr->start };
45462306a36Sopenharmony_ci	struct perf_probe_point result;
45562306a36Sopenharmony_ci	int ret, len = 0;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	memset(&result, 0, sizeof(result));
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	if (lr->end != INT_MAX)
46062306a36Sopenharmony_ci		len = lr->end - lr->start;
46162306a36Sopenharmony_ci	ret = find_alternative_probe_point(dinfo, &pp, &result,
46262306a36Sopenharmony_ci					   target, NULL, user);
46362306a36Sopenharmony_ci	if (!ret) {
46462306a36Sopenharmony_ci		lr->function = result.function;
46562306a36Sopenharmony_ci		lr->file = result.file;
46662306a36Sopenharmony_ci		lr->start = result.line;
46762306a36Sopenharmony_ci		if (lr->end != INT_MAX)
46862306a36Sopenharmony_ci			lr->end = lr->start + len;
46962306a36Sopenharmony_ci		clear_perf_probe_point(&pp);
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci	return ret;
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci#ifdef HAVE_DEBUGINFOD_SUPPORT
47562306a36Sopenharmony_cistatic struct debuginfo *open_from_debuginfod(struct dso *dso, struct nsinfo *nsi,
47662306a36Sopenharmony_ci					      bool silent)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	debuginfod_client *c = debuginfod_begin();
47962306a36Sopenharmony_ci	char sbuild_id[SBUILD_ID_SIZE + 1];
48062306a36Sopenharmony_ci	struct debuginfo *ret = NULL;
48162306a36Sopenharmony_ci	struct nscookie nsc;
48262306a36Sopenharmony_ci	char *path;
48362306a36Sopenharmony_ci	int fd;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (!c)
48662306a36Sopenharmony_ci		return NULL;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	build_id__sprintf(&dso->bid, sbuild_id);
48962306a36Sopenharmony_ci	fd = debuginfod_find_debuginfo(c, (const unsigned char *)sbuild_id,
49062306a36Sopenharmony_ci					0, &path);
49162306a36Sopenharmony_ci	if (fd >= 0)
49262306a36Sopenharmony_ci		close(fd);
49362306a36Sopenharmony_ci	debuginfod_end(c);
49462306a36Sopenharmony_ci	if (fd < 0) {
49562306a36Sopenharmony_ci		if (!silent)
49662306a36Sopenharmony_ci			pr_debug("Failed to find debuginfo in debuginfod.\n");
49762306a36Sopenharmony_ci		return NULL;
49862306a36Sopenharmony_ci	}
49962306a36Sopenharmony_ci	if (!silent)
50062306a36Sopenharmony_ci		pr_debug("Load debuginfo from debuginfod (%s)\n", path);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	nsinfo__mountns_enter(nsi, &nsc);
50362306a36Sopenharmony_ci	ret = debuginfo__new((const char *)path);
50462306a36Sopenharmony_ci	nsinfo__mountns_exit(&nsc);
50562306a36Sopenharmony_ci	return ret;
50662306a36Sopenharmony_ci}
50762306a36Sopenharmony_ci#else
50862306a36Sopenharmony_cistatic inline
50962306a36Sopenharmony_cistruct debuginfo *open_from_debuginfod(struct dso *dso __maybe_unused,
51062306a36Sopenharmony_ci				       struct nsinfo *nsi __maybe_unused,
51162306a36Sopenharmony_ci				       bool silent __maybe_unused)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	return NULL;
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci#endif
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci/* Open new debuginfo of given module */
51862306a36Sopenharmony_cistatic struct debuginfo *open_debuginfo(const char *module, struct nsinfo *nsi,
51962306a36Sopenharmony_ci					bool silent)
52062306a36Sopenharmony_ci{
52162306a36Sopenharmony_ci	const char *path = module;
52262306a36Sopenharmony_ci	char reason[STRERR_BUFSIZE];
52362306a36Sopenharmony_ci	struct debuginfo *ret = NULL;
52462306a36Sopenharmony_ci	struct dso *dso = NULL;
52562306a36Sopenharmony_ci	struct nscookie nsc;
52662306a36Sopenharmony_ci	int err;
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	if (!module || !strchr(module, '/')) {
52962306a36Sopenharmony_ci		err = kernel_get_module_dso(module, &dso);
53062306a36Sopenharmony_ci		if (err < 0) {
53162306a36Sopenharmony_ci			if (!dso || dso->load_errno == 0) {
53262306a36Sopenharmony_ci				if (!str_error_r(-err, reason, STRERR_BUFSIZE))
53362306a36Sopenharmony_ci					strcpy(reason, "(unknown)");
53462306a36Sopenharmony_ci			} else
53562306a36Sopenharmony_ci				dso__strerror_load(dso, reason, STRERR_BUFSIZE);
53662306a36Sopenharmony_ci			if (dso)
53762306a36Sopenharmony_ci				ret = open_from_debuginfod(dso, nsi, silent);
53862306a36Sopenharmony_ci			if (ret)
53962306a36Sopenharmony_ci				return ret;
54062306a36Sopenharmony_ci			if (!silent) {
54162306a36Sopenharmony_ci				if (module)
54262306a36Sopenharmony_ci					pr_err("Module %s is not loaded, please specify its full path name.\n", module);
54362306a36Sopenharmony_ci				else
54462306a36Sopenharmony_ci					pr_err("Failed to find the path for the kernel: %s\n", reason);
54562306a36Sopenharmony_ci			}
54662306a36Sopenharmony_ci			return NULL;
54762306a36Sopenharmony_ci		}
54862306a36Sopenharmony_ci		path = dso->long_name;
54962306a36Sopenharmony_ci	}
55062306a36Sopenharmony_ci	nsinfo__mountns_enter(nsi, &nsc);
55162306a36Sopenharmony_ci	ret = debuginfo__new(path);
55262306a36Sopenharmony_ci	if (!ret && !silent) {
55362306a36Sopenharmony_ci		pr_warning("The %s file has no debug information.\n", path);
55462306a36Sopenharmony_ci		if (!module || !strtailcmp(path, ".ko"))
55562306a36Sopenharmony_ci			pr_warning("Rebuild with CONFIG_DEBUG_INFO=y, ");
55662306a36Sopenharmony_ci		else
55762306a36Sopenharmony_ci			pr_warning("Rebuild with -g, ");
55862306a36Sopenharmony_ci		pr_warning("or install an appropriate debuginfo package.\n");
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci	nsinfo__mountns_exit(&nsc);
56162306a36Sopenharmony_ci	return ret;
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci/* For caching the last debuginfo */
56562306a36Sopenharmony_cistatic struct debuginfo *debuginfo_cache;
56662306a36Sopenharmony_cistatic char *debuginfo_cache_path;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_cistatic struct debuginfo *debuginfo_cache__open(const char *module, bool silent)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	const char *path = module;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	/* If the module is NULL, it should be the kernel. */
57362306a36Sopenharmony_ci	if (!module)
57462306a36Sopenharmony_ci		path = "kernel";
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (debuginfo_cache_path && !strcmp(debuginfo_cache_path, path))
57762306a36Sopenharmony_ci		goto out;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	/* Copy module path */
58062306a36Sopenharmony_ci	free(debuginfo_cache_path);
58162306a36Sopenharmony_ci	debuginfo_cache_path = strdup(path);
58262306a36Sopenharmony_ci	if (!debuginfo_cache_path) {
58362306a36Sopenharmony_ci		debuginfo__delete(debuginfo_cache);
58462306a36Sopenharmony_ci		debuginfo_cache = NULL;
58562306a36Sopenharmony_ci		goto out;
58662306a36Sopenharmony_ci	}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	debuginfo_cache = open_debuginfo(module, NULL, silent);
58962306a36Sopenharmony_ci	if (!debuginfo_cache)
59062306a36Sopenharmony_ci		zfree(&debuginfo_cache_path);
59162306a36Sopenharmony_ciout:
59262306a36Sopenharmony_ci	return debuginfo_cache;
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_cistatic void debuginfo_cache__exit(void)
59662306a36Sopenharmony_ci{
59762306a36Sopenharmony_ci	debuginfo__delete(debuginfo_cache);
59862306a36Sopenharmony_ci	debuginfo_cache = NULL;
59962306a36Sopenharmony_ci	zfree(&debuginfo_cache_path);
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cistatic int get_text_start_address(const char *exec, u64 *address,
60462306a36Sopenharmony_ci				  struct nsinfo *nsi)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	Elf *elf;
60762306a36Sopenharmony_ci	GElf_Ehdr ehdr;
60862306a36Sopenharmony_ci	GElf_Shdr shdr;
60962306a36Sopenharmony_ci	int fd, ret = -ENOENT;
61062306a36Sopenharmony_ci	struct nscookie nsc;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	nsinfo__mountns_enter(nsi, &nsc);
61362306a36Sopenharmony_ci	fd = open(exec, O_RDONLY);
61462306a36Sopenharmony_ci	nsinfo__mountns_exit(&nsc);
61562306a36Sopenharmony_ci	if (fd < 0)
61662306a36Sopenharmony_ci		return -errno;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
61962306a36Sopenharmony_ci	if (elf == NULL) {
62062306a36Sopenharmony_ci		ret = -EINVAL;
62162306a36Sopenharmony_ci		goto out_close;
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	if (gelf_getehdr(elf, &ehdr) == NULL)
62562306a36Sopenharmony_ci		goto out;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	if (!elf_section_by_name(elf, &ehdr, &shdr, ".text", NULL))
62862306a36Sopenharmony_ci		goto out;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	*address = shdr.sh_addr - shdr.sh_offset;
63162306a36Sopenharmony_ci	ret = 0;
63262306a36Sopenharmony_ciout:
63362306a36Sopenharmony_ci	elf_end(elf);
63462306a36Sopenharmony_ciout_close:
63562306a36Sopenharmony_ci	close(fd);
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	return ret;
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci/*
64162306a36Sopenharmony_ci * Convert trace point to probe point with debuginfo
64262306a36Sopenharmony_ci */
64362306a36Sopenharmony_cistatic int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp,
64462306a36Sopenharmony_ci					    struct perf_probe_point *pp,
64562306a36Sopenharmony_ci					    bool is_kprobe)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	struct debuginfo *dinfo = NULL;
64862306a36Sopenharmony_ci	u64 stext = 0;
64962306a36Sopenharmony_ci	u64 addr = tp->address;
65062306a36Sopenharmony_ci	int ret = -ENOENT;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	/* convert the address to dwarf address */
65362306a36Sopenharmony_ci	if (!is_kprobe) {
65462306a36Sopenharmony_ci		if (!addr) {
65562306a36Sopenharmony_ci			ret = -EINVAL;
65662306a36Sopenharmony_ci			goto error;
65762306a36Sopenharmony_ci		}
65862306a36Sopenharmony_ci		ret = get_text_start_address(tp->module, &stext, NULL);
65962306a36Sopenharmony_ci		if (ret < 0)
66062306a36Sopenharmony_ci			goto error;
66162306a36Sopenharmony_ci		addr += stext;
66262306a36Sopenharmony_ci	} else if (tp->symbol) {
66362306a36Sopenharmony_ci		/* If the module is given, this returns relative address */
66462306a36Sopenharmony_ci		ret = kernel_get_symbol_address_by_name(tp->symbol, &addr,
66562306a36Sopenharmony_ci							false, !!tp->module);
66662306a36Sopenharmony_ci		if (ret != 0)
66762306a36Sopenharmony_ci			goto error;
66862306a36Sopenharmony_ci		addr += tp->offset;
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	pr_debug("try to find information at %" PRIx64 " in %s\n", addr,
67262306a36Sopenharmony_ci		 tp->module ? : "kernel");
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	dinfo = debuginfo_cache__open(tp->module, verbose <= 0);
67562306a36Sopenharmony_ci	if (dinfo)
67662306a36Sopenharmony_ci		ret = debuginfo__find_probe_point(dinfo, addr, pp);
67762306a36Sopenharmony_ci	else
67862306a36Sopenharmony_ci		ret = -ENOENT;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (ret > 0) {
68162306a36Sopenharmony_ci		pp->retprobe = tp->retprobe;
68262306a36Sopenharmony_ci		return 0;
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_cierror:
68562306a36Sopenharmony_ci	pr_debug("Failed to find corresponding probes from debuginfo.\n");
68662306a36Sopenharmony_ci	return ret ? : -ENOENT;
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci/* Adjust symbol name and address */
69062306a36Sopenharmony_cistatic int post_process_probe_trace_point(struct probe_trace_point *tp,
69162306a36Sopenharmony_ci					   struct map *map, u64 offs)
69262306a36Sopenharmony_ci{
69362306a36Sopenharmony_ci	struct symbol *sym;
69462306a36Sopenharmony_ci	u64 addr = tp->address - offs;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	sym = map__find_symbol(map, addr);
69762306a36Sopenharmony_ci	if (!sym) {
69862306a36Sopenharmony_ci		/*
69962306a36Sopenharmony_ci		 * If the address is in the inittext section, map can not
70062306a36Sopenharmony_ci		 * find it. Ignore it if we are probing offline kernel.
70162306a36Sopenharmony_ci		 */
70262306a36Sopenharmony_ci		return (symbol_conf.ignore_vmlinux_buildid) ? 0 : -ENOENT;
70362306a36Sopenharmony_ci	}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	if (strcmp(sym->name, tp->symbol)) {
70662306a36Sopenharmony_ci		/* If we have no realname, use symbol for it */
70762306a36Sopenharmony_ci		if (!tp->realname)
70862306a36Sopenharmony_ci			tp->realname = tp->symbol;
70962306a36Sopenharmony_ci		else
71062306a36Sopenharmony_ci			free(tp->symbol);
71162306a36Sopenharmony_ci		tp->symbol = strdup(sym->name);
71262306a36Sopenharmony_ci		if (!tp->symbol)
71362306a36Sopenharmony_ci			return -ENOMEM;
71462306a36Sopenharmony_ci	}
71562306a36Sopenharmony_ci	tp->offset = addr - sym->start;
71662306a36Sopenharmony_ci	tp->address -= offs;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	return 0;
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci/*
72262306a36Sopenharmony_ci * Rename DWARF symbols to ELF symbols -- gcc sometimes optimizes functions
72362306a36Sopenharmony_ci * and generate new symbols with suffixes such as .constprop.N or .isra.N
72462306a36Sopenharmony_ci * etc. Since those symbols are not recorded in DWARF, we have to find
72562306a36Sopenharmony_ci * correct generated symbols from offline ELF binary.
72662306a36Sopenharmony_ci * For online kernel or uprobes we don't need this because those are
72762306a36Sopenharmony_ci * rebased on _text, or already a section relative address.
72862306a36Sopenharmony_ci */
72962306a36Sopenharmony_cistatic int
73062306a36Sopenharmony_cipost_process_offline_probe_trace_events(struct probe_trace_event *tevs,
73162306a36Sopenharmony_ci					int ntevs, const char *pathname)
73262306a36Sopenharmony_ci{
73362306a36Sopenharmony_ci	struct map *map;
73462306a36Sopenharmony_ci	u64 stext = 0;
73562306a36Sopenharmony_ci	int i, ret = 0;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	/* Prepare a map for offline binary */
73862306a36Sopenharmony_ci	map = dso__new_map(pathname);
73962306a36Sopenharmony_ci	if (!map || get_text_start_address(pathname, &stext, NULL) < 0) {
74062306a36Sopenharmony_ci		pr_warning("Failed to get ELF symbols for %s\n", pathname);
74162306a36Sopenharmony_ci		return -EINVAL;
74262306a36Sopenharmony_ci	}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	for (i = 0; i < ntevs; i++) {
74562306a36Sopenharmony_ci		ret = post_process_probe_trace_point(&tevs[i].point,
74662306a36Sopenharmony_ci						     map, stext);
74762306a36Sopenharmony_ci		if (ret < 0)
74862306a36Sopenharmony_ci			break;
74962306a36Sopenharmony_ci	}
75062306a36Sopenharmony_ci	map__put(map);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	return ret;
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_cistatic int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
75662306a36Sopenharmony_ci					  int ntevs, const char *exec,
75762306a36Sopenharmony_ci					  struct nsinfo *nsi)
75862306a36Sopenharmony_ci{
75962306a36Sopenharmony_ci	int i, ret = 0;
76062306a36Sopenharmony_ci	u64 stext = 0;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	if (!exec)
76362306a36Sopenharmony_ci		return 0;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	ret = get_text_start_address(exec, &stext, nsi);
76662306a36Sopenharmony_ci	if (ret < 0)
76762306a36Sopenharmony_ci		return ret;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	for (i = 0; i < ntevs && ret >= 0; i++) {
77062306a36Sopenharmony_ci		/* point.address is the address of point.symbol + point.offset */
77162306a36Sopenharmony_ci		tevs[i].point.address -= stext;
77262306a36Sopenharmony_ci		tevs[i].point.module = strdup(exec);
77362306a36Sopenharmony_ci		if (!tevs[i].point.module) {
77462306a36Sopenharmony_ci			ret = -ENOMEM;
77562306a36Sopenharmony_ci			break;
77662306a36Sopenharmony_ci		}
77762306a36Sopenharmony_ci		tevs[i].uprobes = true;
77862306a36Sopenharmony_ci	}
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	return ret;
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_cistatic int
78462306a36Sopenharmony_cipost_process_module_probe_trace_events(struct probe_trace_event *tevs,
78562306a36Sopenharmony_ci				       int ntevs, const char *module,
78662306a36Sopenharmony_ci				       struct debuginfo *dinfo)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	Dwarf_Addr text_offs = 0;
78962306a36Sopenharmony_ci	int i, ret = 0;
79062306a36Sopenharmony_ci	char *mod_name = NULL;
79162306a36Sopenharmony_ci	struct map *map;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	if (!module)
79462306a36Sopenharmony_ci		return 0;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	map = get_target_map(module, NULL, false);
79762306a36Sopenharmony_ci	if (!map || debuginfo__get_text_offset(dinfo, &text_offs, true) < 0) {
79862306a36Sopenharmony_ci		pr_warning("Failed to get ELF symbols for %s\n", module);
79962306a36Sopenharmony_ci		return -EINVAL;
80062306a36Sopenharmony_ci	}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	mod_name = find_module_name(module);
80362306a36Sopenharmony_ci	for (i = 0; i < ntevs; i++) {
80462306a36Sopenharmony_ci		ret = post_process_probe_trace_point(&tevs[i].point,
80562306a36Sopenharmony_ci						map, text_offs);
80662306a36Sopenharmony_ci		if (ret < 0)
80762306a36Sopenharmony_ci			break;
80862306a36Sopenharmony_ci		tevs[i].point.module =
80962306a36Sopenharmony_ci			strdup(mod_name ? mod_name : module);
81062306a36Sopenharmony_ci		if (!tevs[i].point.module) {
81162306a36Sopenharmony_ci			ret = -ENOMEM;
81262306a36Sopenharmony_ci			break;
81362306a36Sopenharmony_ci		}
81462306a36Sopenharmony_ci	}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci	free(mod_name);
81762306a36Sopenharmony_ci	map__put(map);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	return ret;
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cistatic int
82362306a36Sopenharmony_cipost_process_kernel_probe_trace_events(struct probe_trace_event *tevs,
82462306a36Sopenharmony_ci				       int ntevs)
82562306a36Sopenharmony_ci{
82662306a36Sopenharmony_ci	struct ref_reloc_sym *reloc_sym;
82762306a36Sopenharmony_ci	struct map *map;
82862306a36Sopenharmony_ci	char *tmp;
82962306a36Sopenharmony_ci	int i, skipped = 0;
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	/* Skip post process if the target is an offline kernel */
83262306a36Sopenharmony_ci	if (symbol_conf.ignore_vmlinux_buildid)
83362306a36Sopenharmony_ci		return post_process_offline_probe_trace_events(tevs, ntevs,
83462306a36Sopenharmony_ci						symbol_conf.vmlinux_name);
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	reloc_sym = kernel_get_ref_reloc_sym(&map);
83762306a36Sopenharmony_ci	if (!reloc_sym) {
83862306a36Sopenharmony_ci		pr_warning("Relocated base symbol is not found! "
83962306a36Sopenharmony_ci			   "Check /proc/sys/kernel/kptr_restrict\n"
84062306a36Sopenharmony_ci			   "and /proc/sys/kernel/perf_event_paranoid. "
84162306a36Sopenharmony_ci			   "Or run as privileged perf user.\n\n");
84262306a36Sopenharmony_ci		return -EINVAL;
84362306a36Sopenharmony_ci	}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	for (i = 0; i < ntevs; i++) {
84662306a36Sopenharmony_ci		if (!tevs[i].point.address)
84762306a36Sopenharmony_ci			continue;
84862306a36Sopenharmony_ci		if (tevs[i].point.retprobe && !kretprobe_offset_is_supported())
84962306a36Sopenharmony_ci			continue;
85062306a36Sopenharmony_ci		/*
85162306a36Sopenharmony_ci		 * If we found a wrong one, mark it by NULL symbol.
85262306a36Sopenharmony_ci		 * Since addresses in debuginfo is same as objdump, we need
85362306a36Sopenharmony_ci		 * to convert it to addresses on memory.
85462306a36Sopenharmony_ci		 */
85562306a36Sopenharmony_ci		if (kprobe_warn_out_range(tevs[i].point.symbol,
85662306a36Sopenharmony_ci			map__objdump_2mem(map, tevs[i].point.address))) {
85762306a36Sopenharmony_ci			tmp = NULL;
85862306a36Sopenharmony_ci			skipped++;
85962306a36Sopenharmony_ci		} else {
86062306a36Sopenharmony_ci			tmp = strdup(reloc_sym->name);
86162306a36Sopenharmony_ci			if (!tmp)
86262306a36Sopenharmony_ci				return -ENOMEM;
86362306a36Sopenharmony_ci		}
86462306a36Sopenharmony_ci		/* If we have no realname, use symbol for it */
86562306a36Sopenharmony_ci		if (!tevs[i].point.realname)
86662306a36Sopenharmony_ci			tevs[i].point.realname = tevs[i].point.symbol;
86762306a36Sopenharmony_ci		else
86862306a36Sopenharmony_ci			free(tevs[i].point.symbol);
86962306a36Sopenharmony_ci		tevs[i].point.symbol = tmp;
87062306a36Sopenharmony_ci		tevs[i].point.offset = tevs[i].point.address -
87162306a36Sopenharmony_ci			(map__reloc(map) ? reloc_sym->unrelocated_addr :
87262306a36Sopenharmony_ci				      reloc_sym->addr);
87362306a36Sopenharmony_ci	}
87462306a36Sopenharmony_ci	return skipped;
87562306a36Sopenharmony_ci}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_civoid __weak
87862306a36Sopenharmony_ciarch__post_process_probe_trace_events(struct perf_probe_event *pev __maybe_unused,
87962306a36Sopenharmony_ci				      int ntevs __maybe_unused)
88062306a36Sopenharmony_ci{
88162306a36Sopenharmony_ci}
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci/* Post processing the probe events */
88462306a36Sopenharmony_cistatic int post_process_probe_trace_events(struct perf_probe_event *pev,
88562306a36Sopenharmony_ci					   struct probe_trace_event *tevs,
88662306a36Sopenharmony_ci					   int ntevs, const char *module,
88762306a36Sopenharmony_ci					   bool uprobe, struct debuginfo *dinfo)
88862306a36Sopenharmony_ci{
88962306a36Sopenharmony_ci	int ret;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	if (uprobe)
89262306a36Sopenharmony_ci		ret = add_exec_to_probe_trace_events(tevs, ntevs, module,
89362306a36Sopenharmony_ci						     pev->nsi);
89462306a36Sopenharmony_ci	else if (module)
89562306a36Sopenharmony_ci		/* Currently ref_reloc_sym based probe is not for drivers */
89662306a36Sopenharmony_ci		ret = post_process_module_probe_trace_events(tevs, ntevs,
89762306a36Sopenharmony_ci							     module, dinfo);
89862306a36Sopenharmony_ci	else
89962306a36Sopenharmony_ci		ret = post_process_kernel_probe_trace_events(tevs, ntevs);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	if (ret >= 0)
90262306a36Sopenharmony_ci		arch__post_process_probe_trace_events(pev, ntevs);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	return ret;
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci/* Try to find perf_probe_event with debuginfo */
90862306a36Sopenharmony_cistatic int try_to_find_probe_trace_events(struct perf_probe_event *pev,
90962306a36Sopenharmony_ci					  struct probe_trace_event **tevs)
91062306a36Sopenharmony_ci{
91162306a36Sopenharmony_ci	bool need_dwarf = perf_probe_event_need_dwarf(pev);
91262306a36Sopenharmony_ci	struct perf_probe_point tmp;
91362306a36Sopenharmony_ci	struct debuginfo *dinfo;
91462306a36Sopenharmony_ci	int ntevs, ret = 0;
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	/* Workaround for gcc #98776 issue.
91762306a36Sopenharmony_ci	 * Perf failed to add kretprobe event with debuginfo of vmlinux which is
91862306a36Sopenharmony_ci	 * compiled by gcc with -fpatchable-function-entry option enabled. The
91962306a36Sopenharmony_ci	 * same issue with kernel module. The retprobe doesn`t need debuginfo.
92062306a36Sopenharmony_ci	 * This workaround solution use map to query the probe function address
92162306a36Sopenharmony_ci	 * for retprobe event.
92262306a36Sopenharmony_ci	 */
92362306a36Sopenharmony_ci	if (pev->point.retprobe)
92462306a36Sopenharmony_ci		return 0;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	dinfo = open_debuginfo(pev->target, pev->nsi, !need_dwarf);
92762306a36Sopenharmony_ci	if (!dinfo) {
92862306a36Sopenharmony_ci		if (need_dwarf)
92962306a36Sopenharmony_ci			return -ENODATA;
93062306a36Sopenharmony_ci		pr_debug("Could not open debuginfo. Try to use symbols.\n");
93162306a36Sopenharmony_ci		return 0;
93262306a36Sopenharmony_ci	}
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	pr_debug("Try to find probe point from debuginfo.\n");
93562306a36Sopenharmony_ci	/* Searching trace events corresponding to a probe event */
93662306a36Sopenharmony_ci	ntevs = debuginfo__find_trace_events(dinfo, pev, tevs);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	if (ntevs == 0)	{  /* Not found, retry with an alternative */
93962306a36Sopenharmony_ci		ret = get_alternative_probe_event(dinfo, pev, &tmp);
94062306a36Sopenharmony_ci		if (!ret) {
94162306a36Sopenharmony_ci			ntevs = debuginfo__find_trace_events(dinfo, pev, tevs);
94262306a36Sopenharmony_ci			/*
94362306a36Sopenharmony_ci			 * Write back to the original probe_event for
94462306a36Sopenharmony_ci			 * setting appropriate (user given) event name
94562306a36Sopenharmony_ci			 */
94662306a36Sopenharmony_ci			clear_perf_probe_point(&pev->point);
94762306a36Sopenharmony_ci			memcpy(&pev->point, &tmp, sizeof(tmp));
94862306a36Sopenharmony_ci		}
94962306a36Sopenharmony_ci	}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	if (ntevs > 0) {	/* Succeeded to find trace events */
95262306a36Sopenharmony_ci		pr_debug("Found %d probe_trace_events.\n", ntevs);
95362306a36Sopenharmony_ci		ret = post_process_probe_trace_events(pev, *tevs, ntevs,
95462306a36Sopenharmony_ci					pev->target, pev->uprobes, dinfo);
95562306a36Sopenharmony_ci		if (ret < 0 || ret == ntevs) {
95662306a36Sopenharmony_ci			pr_debug("Post processing failed or all events are skipped. (%d)\n", ret);
95762306a36Sopenharmony_ci			clear_probe_trace_events(*tevs, ntevs);
95862306a36Sopenharmony_ci			zfree(tevs);
95962306a36Sopenharmony_ci			ntevs = 0;
96062306a36Sopenharmony_ci		}
96162306a36Sopenharmony_ci	}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	debuginfo__delete(dinfo);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	if (ntevs == 0)	{	/* No error but failed to find probe point. */
96662306a36Sopenharmony_ci		char *probe_point = synthesize_perf_probe_point(&pev->point);
96762306a36Sopenharmony_ci		pr_warning("Probe point '%s' not found.\n", probe_point);
96862306a36Sopenharmony_ci		free(probe_point);
96962306a36Sopenharmony_ci		return -ENODEV;
97062306a36Sopenharmony_ci	} else if (ntevs < 0) {
97162306a36Sopenharmony_ci		/* Error path : ntevs < 0 */
97262306a36Sopenharmony_ci		pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
97362306a36Sopenharmony_ci		if (ntevs == -EBADF)
97462306a36Sopenharmony_ci			pr_warning("Warning: No dwarf info found in the vmlinux - "
97562306a36Sopenharmony_ci				"please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
97662306a36Sopenharmony_ci		if (!need_dwarf) {
97762306a36Sopenharmony_ci			pr_debug("Trying to use symbols.\n");
97862306a36Sopenharmony_ci			return 0;
97962306a36Sopenharmony_ci		}
98062306a36Sopenharmony_ci	}
98162306a36Sopenharmony_ci	return ntevs;
98262306a36Sopenharmony_ci}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci#define LINEBUF_SIZE 256
98562306a36Sopenharmony_ci#define NR_ADDITIONAL_LINES 2
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_cistatic int __show_one_line(FILE *fp, int l, bool skip, bool show_num)
98862306a36Sopenharmony_ci{
98962306a36Sopenharmony_ci	char buf[LINEBUF_SIZE], sbuf[STRERR_BUFSIZE];
99062306a36Sopenharmony_ci	const char *color = show_num ? "" : PERF_COLOR_BLUE;
99162306a36Sopenharmony_ci	const char *prefix = NULL;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	do {
99462306a36Sopenharmony_ci		if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
99562306a36Sopenharmony_ci			goto error;
99662306a36Sopenharmony_ci		if (skip)
99762306a36Sopenharmony_ci			continue;
99862306a36Sopenharmony_ci		if (!prefix) {
99962306a36Sopenharmony_ci			prefix = show_num ? "%7d  " : "         ";
100062306a36Sopenharmony_ci			color_fprintf(stdout, color, prefix, l);
100162306a36Sopenharmony_ci		}
100262306a36Sopenharmony_ci		color_fprintf(stdout, color, "%s", buf);
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci	} while (strchr(buf, '\n') == NULL);
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	return 1;
100762306a36Sopenharmony_cierror:
100862306a36Sopenharmony_ci	if (ferror(fp)) {
100962306a36Sopenharmony_ci		pr_warning("File read error: %s\n",
101062306a36Sopenharmony_ci			   str_error_r(errno, sbuf, sizeof(sbuf)));
101162306a36Sopenharmony_ci		return -1;
101262306a36Sopenharmony_ci	}
101362306a36Sopenharmony_ci	return 0;
101462306a36Sopenharmony_ci}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_cistatic int _show_one_line(FILE *fp, int l, bool skip, bool show_num)
101762306a36Sopenharmony_ci{
101862306a36Sopenharmony_ci	int rv = __show_one_line(fp, l, skip, show_num);
101962306a36Sopenharmony_ci	if (rv == 0) {
102062306a36Sopenharmony_ci		pr_warning("Source file is shorter than expected.\n");
102162306a36Sopenharmony_ci		rv = -1;
102262306a36Sopenharmony_ci	}
102362306a36Sopenharmony_ci	return rv;
102462306a36Sopenharmony_ci}
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci#define show_one_line_with_num(f,l)	_show_one_line(f,l,false,true)
102762306a36Sopenharmony_ci#define show_one_line(f,l)		_show_one_line(f,l,false,false)
102862306a36Sopenharmony_ci#define skip_one_line(f,l)		_show_one_line(f,l,true,false)
102962306a36Sopenharmony_ci#define show_one_line_or_eof(f,l)	__show_one_line(f,l,false,false)
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci/*
103262306a36Sopenharmony_ci * Show line-range always requires debuginfo to find source file and
103362306a36Sopenharmony_ci * line number.
103462306a36Sopenharmony_ci */
103562306a36Sopenharmony_cistatic int __show_line_range(struct line_range *lr, const char *module,
103662306a36Sopenharmony_ci			     bool user)
103762306a36Sopenharmony_ci{
103862306a36Sopenharmony_ci	struct build_id bid;
103962306a36Sopenharmony_ci	int l = 1;
104062306a36Sopenharmony_ci	struct int_node *ln;
104162306a36Sopenharmony_ci	struct debuginfo *dinfo;
104262306a36Sopenharmony_ci	FILE *fp;
104362306a36Sopenharmony_ci	int ret;
104462306a36Sopenharmony_ci	char *tmp;
104562306a36Sopenharmony_ci	char sbuf[STRERR_BUFSIZE];
104662306a36Sopenharmony_ci	char sbuild_id[SBUILD_ID_SIZE] = "";
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	/* Search a line range */
104962306a36Sopenharmony_ci	dinfo = open_debuginfo(module, NULL, false);
105062306a36Sopenharmony_ci	if (!dinfo)
105162306a36Sopenharmony_ci		return -ENOENT;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	ret = debuginfo__find_line_range(dinfo, lr);
105462306a36Sopenharmony_ci	if (!ret) {	/* Not found, retry with an alternative */
105562306a36Sopenharmony_ci		ret = get_alternative_line_range(dinfo, lr, module, user);
105662306a36Sopenharmony_ci		if (!ret)
105762306a36Sopenharmony_ci			ret = debuginfo__find_line_range(dinfo, lr);
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci	if (dinfo->build_id) {
106062306a36Sopenharmony_ci		build_id__init(&bid, dinfo->build_id, BUILD_ID_SIZE);
106162306a36Sopenharmony_ci		build_id__sprintf(&bid, sbuild_id);
106262306a36Sopenharmony_ci	}
106362306a36Sopenharmony_ci	debuginfo__delete(dinfo);
106462306a36Sopenharmony_ci	if (ret == 0 || ret == -ENOENT) {
106562306a36Sopenharmony_ci		pr_warning("Specified source line is not found.\n");
106662306a36Sopenharmony_ci		return -ENOENT;
106762306a36Sopenharmony_ci	} else if (ret < 0) {
106862306a36Sopenharmony_ci		pr_warning("Debuginfo analysis failed.\n");
106962306a36Sopenharmony_ci		return ret;
107062306a36Sopenharmony_ci	}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	/* Convert source file path */
107362306a36Sopenharmony_ci	tmp = lr->path;
107462306a36Sopenharmony_ci	ret = find_source_path(tmp, sbuild_id, lr->comp_dir, &lr->path);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	/* Free old path when new path is assigned */
107762306a36Sopenharmony_ci	if (tmp != lr->path)
107862306a36Sopenharmony_ci		free(tmp);
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	if (ret < 0) {
108162306a36Sopenharmony_ci		pr_warning("Failed to find source file path.\n");
108262306a36Sopenharmony_ci		return ret;
108362306a36Sopenharmony_ci	}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	setup_pager();
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci	if (lr->function)
108862306a36Sopenharmony_ci		fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path,
108962306a36Sopenharmony_ci			lr->start - lr->offset);
109062306a36Sopenharmony_ci	else
109162306a36Sopenharmony_ci		fprintf(stdout, "<%s:%d>\n", lr->path, lr->start);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	fp = fopen(lr->path, "r");
109462306a36Sopenharmony_ci	if (fp == NULL) {
109562306a36Sopenharmony_ci		pr_warning("Failed to open %s: %s\n", lr->path,
109662306a36Sopenharmony_ci			   str_error_r(errno, sbuf, sizeof(sbuf)));
109762306a36Sopenharmony_ci		return -errno;
109862306a36Sopenharmony_ci	}
109962306a36Sopenharmony_ci	/* Skip to starting line number */
110062306a36Sopenharmony_ci	while (l < lr->start) {
110162306a36Sopenharmony_ci		ret = skip_one_line(fp, l++);
110262306a36Sopenharmony_ci		if (ret < 0)
110362306a36Sopenharmony_ci			goto end;
110462306a36Sopenharmony_ci	}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	intlist__for_each_entry(ln, lr->line_list) {
110762306a36Sopenharmony_ci		for (; ln->i > (unsigned long)l; l++) {
110862306a36Sopenharmony_ci			ret = show_one_line(fp, l - lr->offset);
110962306a36Sopenharmony_ci			if (ret < 0)
111062306a36Sopenharmony_ci				goto end;
111162306a36Sopenharmony_ci		}
111262306a36Sopenharmony_ci		ret = show_one_line_with_num(fp, l++ - lr->offset);
111362306a36Sopenharmony_ci		if (ret < 0)
111462306a36Sopenharmony_ci			goto end;
111562306a36Sopenharmony_ci	}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	if (lr->end == INT_MAX)
111862306a36Sopenharmony_ci		lr->end = l + NR_ADDITIONAL_LINES;
111962306a36Sopenharmony_ci	while (l <= lr->end) {
112062306a36Sopenharmony_ci		ret = show_one_line_or_eof(fp, l++ - lr->offset);
112162306a36Sopenharmony_ci		if (ret <= 0)
112262306a36Sopenharmony_ci			break;
112362306a36Sopenharmony_ci	}
112462306a36Sopenharmony_ciend:
112562306a36Sopenharmony_ci	fclose(fp);
112662306a36Sopenharmony_ci	return ret;
112762306a36Sopenharmony_ci}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ciint show_line_range(struct line_range *lr, const char *module,
113062306a36Sopenharmony_ci		    struct nsinfo *nsi, bool user)
113162306a36Sopenharmony_ci{
113262306a36Sopenharmony_ci	int ret;
113362306a36Sopenharmony_ci	struct nscookie nsc;
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	ret = init_probe_symbol_maps(user);
113662306a36Sopenharmony_ci	if (ret < 0)
113762306a36Sopenharmony_ci		return ret;
113862306a36Sopenharmony_ci	nsinfo__mountns_enter(nsi, &nsc);
113962306a36Sopenharmony_ci	ret = __show_line_range(lr, module, user);
114062306a36Sopenharmony_ci	nsinfo__mountns_exit(&nsc);
114162306a36Sopenharmony_ci	exit_probe_symbol_maps();
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	return ret;
114462306a36Sopenharmony_ci}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_cistatic int show_available_vars_at(struct debuginfo *dinfo,
114762306a36Sopenharmony_ci				  struct perf_probe_event *pev,
114862306a36Sopenharmony_ci				  struct strfilter *_filter)
114962306a36Sopenharmony_ci{
115062306a36Sopenharmony_ci	char *buf;
115162306a36Sopenharmony_ci	int ret, i, nvars;
115262306a36Sopenharmony_ci	struct str_node *node;
115362306a36Sopenharmony_ci	struct variable_list *vls = NULL, *vl;
115462306a36Sopenharmony_ci	struct perf_probe_point tmp;
115562306a36Sopenharmony_ci	const char *var;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	buf = synthesize_perf_probe_point(&pev->point);
115862306a36Sopenharmony_ci	if (!buf)
115962306a36Sopenharmony_ci		return -EINVAL;
116062306a36Sopenharmony_ci	pr_debug("Searching variables at %s\n", buf);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	ret = debuginfo__find_available_vars_at(dinfo, pev, &vls);
116362306a36Sopenharmony_ci	if (!ret) {  /* Not found, retry with an alternative */
116462306a36Sopenharmony_ci		ret = get_alternative_probe_event(dinfo, pev, &tmp);
116562306a36Sopenharmony_ci		if (!ret) {
116662306a36Sopenharmony_ci			ret = debuginfo__find_available_vars_at(dinfo, pev,
116762306a36Sopenharmony_ci								&vls);
116862306a36Sopenharmony_ci			/* Release the old probe_point */
116962306a36Sopenharmony_ci			clear_perf_probe_point(&tmp);
117062306a36Sopenharmony_ci		}
117162306a36Sopenharmony_ci	}
117262306a36Sopenharmony_ci	if (ret <= 0) {
117362306a36Sopenharmony_ci		if (ret == 0 || ret == -ENOENT) {
117462306a36Sopenharmony_ci			pr_err("Failed to find the address of %s\n", buf);
117562306a36Sopenharmony_ci			ret = -ENOENT;
117662306a36Sopenharmony_ci		} else
117762306a36Sopenharmony_ci			pr_warning("Debuginfo analysis failed.\n");
117862306a36Sopenharmony_ci		goto end;
117962306a36Sopenharmony_ci	}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	/* Some variables are found */
118262306a36Sopenharmony_ci	fprintf(stdout, "Available variables at %s\n", buf);
118362306a36Sopenharmony_ci	for (i = 0; i < ret; i++) {
118462306a36Sopenharmony_ci		vl = &vls[i];
118562306a36Sopenharmony_ci		/*
118662306a36Sopenharmony_ci		 * A probe point might be converted to
118762306a36Sopenharmony_ci		 * several trace points.
118862306a36Sopenharmony_ci		 */
118962306a36Sopenharmony_ci		fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
119062306a36Sopenharmony_ci			vl->point.offset);
119162306a36Sopenharmony_ci		zfree(&vl->point.symbol);
119262306a36Sopenharmony_ci		nvars = 0;
119362306a36Sopenharmony_ci		if (vl->vars) {
119462306a36Sopenharmony_ci			strlist__for_each_entry(node, vl->vars) {
119562306a36Sopenharmony_ci				var = strchr(node->s, '\t') + 1;
119662306a36Sopenharmony_ci				if (strfilter__compare(_filter, var)) {
119762306a36Sopenharmony_ci					fprintf(stdout, "\t\t%s\n", node->s);
119862306a36Sopenharmony_ci					nvars++;
119962306a36Sopenharmony_ci				}
120062306a36Sopenharmony_ci			}
120162306a36Sopenharmony_ci			strlist__delete(vl->vars);
120262306a36Sopenharmony_ci		}
120362306a36Sopenharmony_ci		if (nvars == 0)
120462306a36Sopenharmony_ci			fprintf(stdout, "\t\t(No matched variables)\n");
120562306a36Sopenharmony_ci	}
120662306a36Sopenharmony_ci	free(vls);
120762306a36Sopenharmony_ciend:
120862306a36Sopenharmony_ci	free(buf);
120962306a36Sopenharmony_ci	return ret;
121062306a36Sopenharmony_ci}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci/* Show available variables on given probe point */
121362306a36Sopenharmony_ciint show_available_vars(struct perf_probe_event *pevs, int npevs,
121462306a36Sopenharmony_ci			struct strfilter *_filter)
121562306a36Sopenharmony_ci{
121662306a36Sopenharmony_ci	int i, ret = 0;
121762306a36Sopenharmony_ci	struct debuginfo *dinfo;
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	ret = init_probe_symbol_maps(pevs->uprobes);
122062306a36Sopenharmony_ci	if (ret < 0)
122162306a36Sopenharmony_ci		return ret;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	dinfo = open_debuginfo(pevs->target, pevs->nsi, false);
122462306a36Sopenharmony_ci	if (!dinfo) {
122562306a36Sopenharmony_ci		ret = -ENOENT;
122662306a36Sopenharmony_ci		goto out;
122762306a36Sopenharmony_ci	}
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	setup_pager();
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	for (i = 0; i < npevs && ret >= 0; i++)
123262306a36Sopenharmony_ci		ret = show_available_vars_at(dinfo, &pevs[i], _filter);
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	debuginfo__delete(dinfo);
123562306a36Sopenharmony_ciout:
123662306a36Sopenharmony_ci	exit_probe_symbol_maps();
123762306a36Sopenharmony_ci	return ret;
123862306a36Sopenharmony_ci}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci#else	/* !HAVE_DWARF_SUPPORT */
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_cistatic void debuginfo_cache__exit(void)
124362306a36Sopenharmony_ci{
124462306a36Sopenharmony_ci}
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_cistatic int
124762306a36Sopenharmony_cifind_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused,
124862306a36Sopenharmony_ci				 struct perf_probe_point *pp __maybe_unused,
124962306a36Sopenharmony_ci				 bool is_kprobe __maybe_unused)
125062306a36Sopenharmony_ci{
125162306a36Sopenharmony_ci	return -ENOSYS;
125262306a36Sopenharmony_ci}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_cistatic int try_to_find_probe_trace_events(struct perf_probe_event *pev,
125562306a36Sopenharmony_ci				struct probe_trace_event **tevs __maybe_unused)
125662306a36Sopenharmony_ci{
125762306a36Sopenharmony_ci	if (perf_probe_event_need_dwarf(pev)) {
125862306a36Sopenharmony_ci		pr_warning("Debuginfo-analysis is not supported.\n");
125962306a36Sopenharmony_ci		return -ENOSYS;
126062306a36Sopenharmony_ci	}
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	return 0;
126362306a36Sopenharmony_ci}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ciint show_line_range(struct line_range *lr __maybe_unused,
126662306a36Sopenharmony_ci		    const char *module __maybe_unused,
126762306a36Sopenharmony_ci		    struct nsinfo *nsi __maybe_unused,
126862306a36Sopenharmony_ci		    bool user __maybe_unused)
126962306a36Sopenharmony_ci{
127062306a36Sopenharmony_ci	pr_warning("Debuginfo-analysis is not supported.\n");
127162306a36Sopenharmony_ci	return -ENOSYS;
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ciint show_available_vars(struct perf_probe_event *pevs __maybe_unused,
127562306a36Sopenharmony_ci			int npevs __maybe_unused,
127662306a36Sopenharmony_ci			struct strfilter *filter __maybe_unused)
127762306a36Sopenharmony_ci{
127862306a36Sopenharmony_ci	pr_warning("Debuginfo-analysis is not supported.\n");
127962306a36Sopenharmony_ci	return -ENOSYS;
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci#endif
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_civoid line_range__clear(struct line_range *lr)
128462306a36Sopenharmony_ci{
128562306a36Sopenharmony_ci	zfree(&lr->function);
128662306a36Sopenharmony_ci	zfree(&lr->file);
128762306a36Sopenharmony_ci	zfree(&lr->path);
128862306a36Sopenharmony_ci	zfree(&lr->comp_dir);
128962306a36Sopenharmony_ci	intlist__delete(lr->line_list);
129062306a36Sopenharmony_ci}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ciint line_range__init(struct line_range *lr)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	memset(lr, 0, sizeof(*lr));
129562306a36Sopenharmony_ci	lr->line_list = intlist__new(NULL);
129662306a36Sopenharmony_ci	if (!lr->line_list)
129762306a36Sopenharmony_ci		return -ENOMEM;
129862306a36Sopenharmony_ci	else
129962306a36Sopenharmony_ci		return 0;
130062306a36Sopenharmony_ci}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_cistatic int parse_line_num(char **ptr, int *val, const char *what)
130362306a36Sopenharmony_ci{
130462306a36Sopenharmony_ci	const char *start = *ptr;
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	errno = 0;
130762306a36Sopenharmony_ci	*val = strtol(*ptr, ptr, 0);
130862306a36Sopenharmony_ci	if (errno || *ptr == start) {
130962306a36Sopenharmony_ci		semantic_error("'%s' is not a valid number.\n", what);
131062306a36Sopenharmony_ci		return -EINVAL;
131162306a36Sopenharmony_ci	}
131262306a36Sopenharmony_ci	return 0;
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci/* Check the name is good for event, group or function */
131662306a36Sopenharmony_cistatic bool is_c_func_name(const char *name)
131762306a36Sopenharmony_ci{
131862306a36Sopenharmony_ci	if (!isalpha(*name) && *name != '_')
131962306a36Sopenharmony_ci		return false;
132062306a36Sopenharmony_ci	while (*++name != '\0') {
132162306a36Sopenharmony_ci		if (!isalpha(*name) && !isdigit(*name) && *name != '_')
132262306a36Sopenharmony_ci			return false;
132362306a36Sopenharmony_ci	}
132462306a36Sopenharmony_ci	return true;
132562306a36Sopenharmony_ci}
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci/*
132862306a36Sopenharmony_ci * Stuff 'lr' according to the line range described by 'arg'.
132962306a36Sopenharmony_ci * The line range syntax is described by:
133062306a36Sopenharmony_ci *
133162306a36Sopenharmony_ci *         SRC[:SLN[+NUM|-ELN]]
133262306a36Sopenharmony_ci *         FNC[@SRC][:SLN[+NUM|-ELN]]
133362306a36Sopenharmony_ci */
133462306a36Sopenharmony_ciint parse_line_range_desc(const char *arg, struct line_range *lr)
133562306a36Sopenharmony_ci{
133662306a36Sopenharmony_ci	char *range, *file, *name = strdup(arg);
133762306a36Sopenharmony_ci	int err;
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	if (!name)
134062306a36Sopenharmony_ci		return -ENOMEM;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	lr->start = 0;
134362306a36Sopenharmony_ci	lr->end = INT_MAX;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	range = strchr(name, ':');
134662306a36Sopenharmony_ci	if (range) {
134762306a36Sopenharmony_ci		*range++ = '\0';
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci		err = parse_line_num(&range, &lr->start, "start line");
135062306a36Sopenharmony_ci		if (err)
135162306a36Sopenharmony_ci			goto err;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci		if (*range == '+' || *range == '-') {
135462306a36Sopenharmony_ci			const char c = *range++;
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci			err = parse_line_num(&range, &lr->end, "end line");
135762306a36Sopenharmony_ci			if (err)
135862306a36Sopenharmony_ci				goto err;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci			if (c == '+') {
136162306a36Sopenharmony_ci				lr->end += lr->start;
136262306a36Sopenharmony_ci				/*
136362306a36Sopenharmony_ci				 * Adjust the number of lines here.
136462306a36Sopenharmony_ci				 * If the number of lines == 1, the
136562306a36Sopenharmony_ci				 * end of line should be equal to
136662306a36Sopenharmony_ci				 * the start of line.
136762306a36Sopenharmony_ci				 */
136862306a36Sopenharmony_ci				lr->end--;
136962306a36Sopenharmony_ci			}
137062306a36Sopenharmony_ci		}
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci		pr_debug("Line range is %d to %d\n", lr->start, lr->end);
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci		err = -EINVAL;
137562306a36Sopenharmony_ci		if (lr->start > lr->end) {
137662306a36Sopenharmony_ci			semantic_error("Start line must be smaller"
137762306a36Sopenharmony_ci				       " than end line.\n");
137862306a36Sopenharmony_ci			goto err;
137962306a36Sopenharmony_ci		}
138062306a36Sopenharmony_ci		if (*range != '\0') {
138162306a36Sopenharmony_ci			semantic_error("Tailing with invalid str '%s'.\n", range);
138262306a36Sopenharmony_ci			goto err;
138362306a36Sopenharmony_ci		}
138462306a36Sopenharmony_ci	}
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	file = strchr(name, '@');
138762306a36Sopenharmony_ci	if (file) {
138862306a36Sopenharmony_ci		*file = '\0';
138962306a36Sopenharmony_ci		lr->file = strdup(++file);
139062306a36Sopenharmony_ci		if (lr->file == NULL) {
139162306a36Sopenharmony_ci			err = -ENOMEM;
139262306a36Sopenharmony_ci			goto err;
139362306a36Sopenharmony_ci		}
139462306a36Sopenharmony_ci		lr->function = name;
139562306a36Sopenharmony_ci	} else if (strchr(name, '/') || strchr(name, '.'))
139662306a36Sopenharmony_ci		lr->file = name;
139762306a36Sopenharmony_ci	else if (is_c_func_name(name))/* We reuse it for checking funcname */
139862306a36Sopenharmony_ci		lr->function = name;
139962306a36Sopenharmony_ci	else {	/* Invalid name */
140062306a36Sopenharmony_ci		semantic_error("'%s' is not a valid function name.\n", name);
140162306a36Sopenharmony_ci		err = -EINVAL;
140262306a36Sopenharmony_ci		goto err;
140362306a36Sopenharmony_ci	}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	return 0;
140662306a36Sopenharmony_cierr:
140762306a36Sopenharmony_ci	free(name);
140862306a36Sopenharmony_ci	return err;
140962306a36Sopenharmony_ci}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_cistatic int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev)
141262306a36Sopenharmony_ci{
141362306a36Sopenharmony_ci	char *ptr;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	ptr = strpbrk_esc(*arg, ":");
141662306a36Sopenharmony_ci	if (ptr) {
141762306a36Sopenharmony_ci		*ptr = '\0';
141862306a36Sopenharmony_ci		if (!pev->sdt && !is_c_func_name(*arg))
141962306a36Sopenharmony_ci			goto ng_name;
142062306a36Sopenharmony_ci		pev->group = strdup_esc(*arg);
142162306a36Sopenharmony_ci		if (!pev->group)
142262306a36Sopenharmony_ci			return -ENOMEM;
142362306a36Sopenharmony_ci		*arg = ptr + 1;
142462306a36Sopenharmony_ci	} else
142562306a36Sopenharmony_ci		pev->group = NULL;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	pev->event = strdup_esc(*arg);
142862306a36Sopenharmony_ci	if (pev->event == NULL)
142962306a36Sopenharmony_ci		return -ENOMEM;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	if (!pev->sdt && !is_c_func_name(pev->event)) {
143262306a36Sopenharmony_ci		zfree(&pev->event);
143362306a36Sopenharmony_cing_name:
143462306a36Sopenharmony_ci		zfree(&pev->group);
143562306a36Sopenharmony_ci		semantic_error("%s is bad for event name -it must "
143662306a36Sopenharmony_ci			       "follow C symbol-naming rule.\n", *arg);
143762306a36Sopenharmony_ci		return -EINVAL;
143862306a36Sopenharmony_ci	}
143962306a36Sopenharmony_ci	return 0;
144062306a36Sopenharmony_ci}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci/* Parse probepoint definition. */
144362306a36Sopenharmony_cistatic int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
144462306a36Sopenharmony_ci{
144562306a36Sopenharmony_ci	struct perf_probe_point *pp = &pev->point;
144662306a36Sopenharmony_ci	char *ptr, *tmp;
144762306a36Sopenharmony_ci	char c, nc = 0;
144862306a36Sopenharmony_ci	bool file_spec = false;
144962306a36Sopenharmony_ci	int ret;
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	/*
145262306a36Sopenharmony_ci	 * <Syntax>
145362306a36Sopenharmony_ci	 * perf probe [GRP:][EVENT=]SRC[:LN|;PTN]
145462306a36Sopenharmony_ci	 * perf probe [GRP:][EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
145562306a36Sopenharmony_ci	 * perf probe %[GRP:]SDT_EVENT
145662306a36Sopenharmony_ci	 */
145762306a36Sopenharmony_ci	if (!arg)
145862306a36Sopenharmony_ci		return -EINVAL;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	if (is_sdt_event(arg)) {
146162306a36Sopenharmony_ci		pev->sdt = true;
146262306a36Sopenharmony_ci		if (arg[0] == '%')
146362306a36Sopenharmony_ci			arg++;
146462306a36Sopenharmony_ci	}
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	ptr = strpbrk_esc(arg, ";=@+%");
146762306a36Sopenharmony_ci	if (pev->sdt) {
146862306a36Sopenharmony_ci		if (ptr) {
146962306a36Sopenharmony_ci			if (*ptr != '@') {
147062306a36Sopenharmony_ci				semantic_error("%s must be an SDT name.\n",
147162306a36Sopenharmony_ci					       arg);
147262306a36Sopenharmony_ci				return -EINVAL;
147362306a36Sopenharmony_ci			}
147462306a36Sopenharmony_ci			/* This must be a target file name or build id */
147562306a36Sopenharmony_ci			tmp = build_id_cache__complement(ptr + 1);
147662306a36Sopenharmony_ci			if (tmp) {
147762306a36Sopenharmony_ci				pev->target = build_id_cache__origname(tmp);
147862306a36Sopenharmony_ci				free(tmp);
147962306a36Sopenharmony_ci			} else
148062306a36Sopenharmony_ci				pev->target = strdup_esc(ptr + 1);
148162306a36Sopenharmony_ci			if (!pev->target)
148262306a36Sopenharmony_ci				return -ENOMEM;
148362306a36Sopenharmony_ci			*ptr = '\0';
148462306a36Sopenharmony_ci		}
148562306a36Sopenharmony_ci		ret = parse_perf_probe_event_name(&arg, pev);
148662306a36Sopenharmony_ci		if (ret == 0) {
148762306a36Sopenharmony_ci			if (asprintf(&pev->point.function, "%%%s", pev->event) < 0)
148862306a36Sopenharmony_ci				ret = -errno;
148962306a36Sopenharmony_ci		}
149062306a36Sopenharmony_ci		return ret;
149162306a36Sopenharmony_ci	}
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	if (ptr && *ptr == '=') {	/* Event name */
149462306a36Sopenharmony_ci		*ptr = '\0';
149562306a36Sopenharmony_ci		tmp = ptr + 1;
149662306a36Sopenharmony_ci		ret = parse_perf_probe_event_name(&arg, pev);
149762306a36Sopenharmony_ci		if (ret < 0)
149862306a36Sopenharmony_ci			return ret;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci		arg = tmp;
150162306a36Sopenharmony_ci	}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	/*
150462306a36Sopenharmony_ci	 * Check arg is function or file name and copy it.
150562306a36Sopenharmony_ci	 *
150662306a36Sopenharmony_ci	 * We consider arg to be a file spec if and only if it satisfies
150762306a36Sopenharmony_ci	 * all of the below criteria::
150862306a36Sopenharmony_ci	 * - it does not include any of "+@%",
150962306a36Sopenharmony_ci	 * - it includes one of ":;", and
151062306a36Sopenharmony_ci	 * - it has a period '.' in the name.
151162306a36Sopenharmony_ci	 *
151262306a36Sopenharmony_ci	 * Otherwise, we consider arg to be a function specification.
151362306a36Sopenharmony_ci	 */
151462306a36Sopenharmony_ci	if (!strpbrk_esc(arg, "+@%")) {
151562306a36Sopenharmony_ci		ptr = strpbrk_esc(arg, ";:");
151662306a36Sopenharmony_ci		/* This is a file spec if it includes a '.' before ; or : */
151762306a36Sopenharmony_ci		if (ptr && memchr(arg, '.', ptr - arg))
151862306a36Sopenharmony_ci			file_spec = true;
151962306a36Sopenharmony_ci	}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	ptr = strpbrk_esc(arg, ";:+@%");
152262306a36Sopenharmony_ci	if (ptr) {
152362306a36Sopenharmony_ci		nc = *ptr;
152462306a36Sopenharmony_ci		*ptr++ = '\0';
152562306a36Sopenharmony_ci	}
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	if (arg[0] == '\0')
152862306a36Sopenharmony_ci		tmp = NULL;
152962306a36Sopenharmony_ci	else {
153062306a36Sopenharmony_ci		tmp = strdup_esc(arg);
153162306a36Sopenharmony_ci		if (tmp == NULL)
153262306a36Sopenharmony_ci			return -ENOMEM;
153362306a36Sopenharmony_ci	}
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	if (file_spec)
153662306a36Sopenharmony_ci		pp->file = tmp;
153762306a36Sopenharmony_ci	else {
153862306a36Sopenharmony_ci		pp->function = tmp;
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci		/*
154162306a36Sopenharmony_ci		 * Keep pp->function even if this is absolute address,
154262306a36Sopenharmony_ci		 * so it can mark whether abs_address is valid.
154362306a36Sopenharmony_ci		 * Which make 'perf probe lib.bin 0x0' possible.
154462306a36Sopenharmony_ci		 *
154562306a36Sopenharmony_ci		 * Note that checking length of tmp is not needed
154662306a36Sopenharmony_ci		 * because when we access tmp[1] we know tmp[0] is '0',
154762306a36Sopenharmony_ci		 * so tmp[1] should always valid (but could be '\0').
154862306a36Sopenharmony_ci		 */
154962306a36Sopenharmony_ci		if (tmp && !strncmp(tmp, "0x", 2)) {
155062306a36Sopenharmony_ci			pp->abs_address = strtoull(pp->function, &tmp, 0);
155162306a36Sopenharmony_ci			if (*tmp != '\0') {
155262306a36Sopenharmony_ci				semantic_error("Invalid absolute address.\n");
155362306a36Sopenharmony_ci				return -EINVAL;
155462306a36Sopenharmony_ci			}
155562306a36Sopenharmony_ci		}
155662306a36Sopenharmony_ci	}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	/* Parse other options */
155962306a36Sopenharmony_ci	while (ptr) {
156062306a36Sopenharmony_ci		arg = ptr;
156162306a36Sopenharmony_ci		c = nc;
156262306a36Sopenharmony_ci		if (c == ';') {	/* Lazy pattern must be the last part */
156362306a36Sopenharmony_ci			pp->lazy_line = strdup(arg); /* let leave escapes */
156462306a36Sopenharmony_ci			if (pp->lazy_line == NULL)
156562306a36Sopenharmony_ci				return -ENOMEM;
156662306a36Sopenharmony_ci			break;
156762306a36Sopenharmony_ci		}
156862306a36Sopenharmony_ci		ptr = strpbrk_esc(arg, ";:+@%");
156962306a36Sopenharmony_ci		if (ptr) {
157062306a36Sopenharmony_ci			nc = *ptr;
157162306a36Sopenharmony_ci			*ptr++ = '\0';
157262306a36Sopenharmony_ci		}
157362306a36Sopenharmony_ci		switch (c) {
157462306a36Sopenharmony_ci		case ':':	/* Line number */
157562306a36Sopenharmony_ci			pp->line = strtoul(arg, &tmp, 0);
157662306a36Sopenharmony_ci			if (*tmp != '\0') {
157762306a36Sopenharmony_ci				semantic_error("There is non-digit char"
157862306a36Sopenharmony_ci					       " in line number.\n");
157962306a36Sopenharmony_ci				return -EINVAL;
158062306a36Sopenharmony_ci			}
158162306a36Sopenharmony_ci			break;
158262306a36Sopenharmony_ci		case '+':	/* Byte offset from a symbol */
158362306a36Sopenharmony_ci			pp->offset = strtoul(arg, &tmp, 0);
158462306a36Sopenharmony_ci			if (*tmp != '\0') {
158562306a36Sopenharmony_ci				semantic_error("There is non-digit character"
158662306a36Sopenharmony_ci						" in offset.\n");
158762306a36Sopenharmony_ci				return -EINVAL;
158862306a36Sopenharmony_ci			}
158962306a36Sopenharmony_ci			break;
159062306a36Sopenharmony_ci		case '@':	/* File name */
159162306a36Sopenharmony_ci			if (pp->file) {
159262306a36Sopenharmony_ci				semantic_error("SRC@SRC is not allowed.\n");
159362306a36Sopenharmony_ci				return -EINVAL;
159462306a36Sopenharmony_ci			}
159562306a36Sopenharmony_ci			pp->file = strdup_esc(arg);
159662306a36Sopenharmony_ci			if (pp->file == NULL)
159762306a36Sopenharmony_ci				return -ENOMEM;
159862306a36Sopenharmony_ci			break;
159962306a36Sopenharmony_ci		case '%':	/* Probe places */
160062306a36Sopenharmony_ci			if (strcmp(arg, "return") == 0) {
160162306a36Sopenharmony_ci				pp->retprobe = 1;
160262306a36Sopenharmony_ci			} else {	/* Others not supported yet */
160362306a36Sopenharmony_ci				semantic_error("%%%s is not supported.\n", arg);
160462306a36Sopenharmony_ci				return -ENOTSUP;
160562306a36Sopenharmony_ci			}
160662306a36Sopenharmony_ci			break;
160762306a36Sopenharmony_ci		default:	/* Buggy case */
160862306a36Sopenharmony_ci			pr_err("This program has a bug at %s:%d.\n",
160962306a36Sopenharmony_ci				__FILE__, __LINE__);
161062306a36Sopenharmony_ci			return -ENOTSUP;
161162306a36Sopenharmony_ci			break;
161262306a36Sopenharmony_ci		}
161362306a36Sopenharmony_ci	}
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci	/* Exclusion check */
161662306a36Sopenharmony_ci	if (pp->lazy_line && pp->line) {
161762306a36Sopenharmony_ci		semantic_error("Lazy pattern can't be used with"
161862306a36Sopenharmony_ci			       " line number.\n");
161962306a36Sopenharmony_ci		return -EINVAL;
162062306a36Sopenharmony_ci	}
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	if (pp->lazy_line && pp->offset) {
162362306a36Sopenharmony_ci		semantic_error("Lazy pattern can't be used with offset.\n");
162462306a36Sopenharmony_ci		return -EINVAL;
162562306a36Sopenharmony_ci	}
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	if (pp->line && pp->offset) {
162862306a36Sopenharmony_ci		semantic_error("Offset can't be used with line number.\n");
162962306a36Sopenharmony_ci		return -EINVAL;
163062306a36Sopenharmony_ci	}
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	if (!pp->line && !pp->lazy_line && pp->file && !pp->function) {
163362306a36Sopenharmony_ci		semantic_error("File always requires line number or "
163462306a36Sopenharmony_ci			       "lazy pattern.\n");
163562306a36Sopenharmony_ci		return -EINVAL;
163662306a36Sopenharmony_ci	}
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci	if (pp->offset && !pp->function) {
163962306a36Sopenharmony_ci		semantic_error("Offset requires an entry function.\n");
164062306a36Sopenharmony_ci		return -EINVAL;
164162306a36Sopenharmony_ci	}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) {
164462306a36Sopenharmony_ci		semantic_error("Offset/Line/Lazy pattern can't be used with "
164562306a36Sopenharmony_ci			       "return probe.\n");
164662306a36Sopenharmony_ci		return -EINVAL;
164762306a36Sopenharmony_ci	}
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n",
165062306a36Sopenharmony_ci		 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
165162306a36Sopenharmony_ci		 pp->lazy_line);
165262306a36Sopenharmony_ci	return 0;
165362306a36Sopenharmony_ci}
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci/* Parse perf-probe event argument */
165662306a36Sopenharmony_cistatic int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
165762306a36Sopenharmony_ci{
165862306a36Sopenharmony_ci	char *tmp, *goodname;
165962306a36Sopenharmony_ci	struct perf_probe_arg_field **fieldp;
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci	pr_debug("parsing arg: %s into ", str);
166262306a36Sopenharmony_ci
166362306a36Sopenharmony_ci	tmp = strchr(str, '=');
166462306a36Sopenharmony_ci	if (tmp) {
166562306a36Sopenharmony_ci		arg->name = strndup(str, tmp - str);
166662306a36Sopenharmony_ci		if (arg->name == NULL)
166762306a36Sopenharmony_ci			return -ENOMEM;
166862306a36Sopenharmony_ci		pr_debug("name:%s ", arg->name);
166962306a36Sopenharmony_ci		str = tmp + 1;
167062306a36Sopenharmony_ci	}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	tmp = strchr(str, '@');
167362306a36Sopenharmony_ci	if (tmp && tmp != str && !strcmp(tmp + 1, "user")) { /* user attr */
167462306a36Sopenharmony_ci		if (!user_access_is_supported()) {
167562306a36Sopenharmony_ci			semantic_error("ftrace does not support user access\n");
167662306a36Sopenharmony_ci			return -EINVAL;
167762306a36Sopenharmony_ci		}
167862306a36Sopenharmony_ci		*tmp = '\0';
167962306a36Sopenharmony_ci		arg->user_access = true;
168062306a36Sopenharmony_ci		pr_debug("user_access ");
168162306a36Sopenharmony_ci	}
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	tmp = strchr(str, ':');
168462306a36Sopenharmony_ci	if (tmp) {	/* Type setting */
168562306a36Sopenharmony_ci		*tmp = '\0';
168662306a36Sopenharmony_ci		arg->type = strdup(tmp + 1);
168762306a36Sopenharmony_ci		if (arg->type == NULL)
168862306a36Sopenharmony_ci			return -ENOMEM;
168962306a36Sopenharmony_ci		pr_debug("type:%s ", arg->type);
169062306a36Sopenharmony_ci	}
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	tmp = strpbrk(str, "-.[");
169362306a36Sopenharmony_ci	if (!is_c_varname(str) || !tmp) {
169462306a36Sopenharmony_ci		/* A variable, register, symbol or special value */
169562306a36Sopenharmony_ci		arg->var = strdup(str);
169662306a36Sopenharmony_ci		if (arg->var == NULL)
169762306a36Sopenharmony_ci			return -ENOMEM;
169862306a36Sopenharmony_ci		pr_debug("%s\n", arg->var);
169962306a36Sopenharmony_ci		return 0;
170062306a36Sopenharmony_ci	}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	/* Structure fields or array element */
170362306a36Sopenharmony_ci	arg->var = strndup(str, tmp - str);
170462306a36Sopenharmony_ci	if (arg->var == NULL)
170562306a36Sopenharmony_ci		return -ENOMEM;
170662306a36Sopenharmony_ci	goodname = arg->var;
170762306a36Sopenharmony_ci	pr_debug("%s, ", arg->var);
170862306a36Sopenharmony_ci	fieldp = &arg->field;
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci	do {
171162306a36Sopenharmony_ci		*fieldp = zalloc(sizeof(struct perf_probe_arg_field));
171262306a36Sopenharmony_ci		if (*fieldp == NULL)
171362306a36Sopenharmony_ci			return -ENOMEM;
171462306a36Sopenharmony_ci		if (*tmp == '[') {	/* Array */
171562306a36Sopenharmony_ci			str = tmp;
171662306a36Sopenharmony_ci			(*fieldp)->index = strtol(str + 1, &tmp, 0);
171762306a36Sopenharmony_ci			(*fieldp)->ref = true;
171862306a36Sopenharmony_ci			if (*tmp != ']' || tmp == str + 1) {
171962306a36Sopenharmony_ci				semantic_error("Array index must be a"
172062306a36Sopenharmony_ci						" number.\n");
172162306a36Sopenharmony_ci				return -EINVAL;
172262306a36Sopenharmony_ci			}
172362306a36Sopenharmony_ci			tmp++;
172462306a36Sopenharmony_ci			if (*tmp == '\0')
172562306a36Sopenharmony_ci				tmp = NULL;
172662306a36Sopenharmony_ci		} else {		/* Structure */
172762306a36Sopenharmony_ci			if (*tmp == '.') {
172862306a36Sopenharmony_ci				str = tmp + 1;
172962306a36Sopenharmony_ci				(*fieldp)->ref = false;
173062306a36Sopenharmony_ci			} else if (tmp[1] == '>') {
173162306a36Sopenharmony_ci				str = tmp + 2;
173262306a36Sopenharmony_ci				(*fieldp)->ref = true;
173362306a36Sopenharmony_ci			} else {
173462306a36Sopenharmony_ci				semantic_error("Argument parse error: %s\n",
173562306a36Sopenharmony_ci					       str);
173662306a36Sopenharmony_ci				return -EINVAL;
173762306a36Sopenharmony_ci			}
173862306a36Sopenharmony_ci			tmp = strpbrk(str, "-.[");
173962306a36Sopenharmony_ci		}
174062306a36Sopenharmony_ci		if (tmp) {
174162306a36Sopenharmony_ci			(*fieldp)->name = strndup(str, tmp - str);
174262306a36Sopenharmony_ci			if ((*fieldp)->name == NULL)
174362306a36Sopenharmony_ci				return -ENOMEM;
174462306a36Sopenharmony_ci			if (*str != '[')
174562306a36Sopenharmony_ci				goodname = (*fieldp)->name;
174662306a36Sopenharmony_ci			pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
174762306a36Sopenharmony_ci			fieldp = &(*fieldp)->next;
174862306a36Sopenharmony_ci		}
174962306a36Sopenharmony_ci	} while (tmp);
175062306a36Sopenharmony_ci	(*fieldp)->name = strdup(str);
175162306a36Sopenharmony_ci	if ((*fieldp)->name == NULL)
175262306a36Sopenharmony_ci		return -ENOMEM;
175362306a36Sopenharmony_ci	if (*str != '[')
175462306a36Sopenharmony_ci		goodname = (*fieldp)->name;
175562306a36Sopenharmony_ci	pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	/* If no name is specified, set the last field name (not array index)*/
175862306a36Sopenharmony_ci	if (!arg->name) {
175962306a36Sopenharmony_ci		arg->name = strdup(goodname);
176062306a36Sopenharmony_ci		if (arg->name == NULL)
176162306a36Sopenharmony_ci			return -ENOMEM;
176262306a36Sopenharmony_ci	}
176362306a36Sopenharmony_ci	return 0;
176462306a36Sopenharmony_ci}
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci/* Parse perf-probe event command */
176762306a36Sopenharmony_ciint parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
176862306a36Sopenharmony_ci{
176962306a36Sopenharmony_ci	char **argv;
177062306a36Sopenharmony_ci	int argc, i, ret = 0;
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	argv = argv_split(cmd, &argc);
177362306a36Sopenharmony_ci	if (!argv) {
177462306a36Sopenharmony_ci		pr_debug("Failed to split arguments.\n");
177562306a36Sopenharmony_ci		return -ENOMEM;
177662306a36Sopenharmony_ci	}
177762306a36Sopenharmony_ci	if (argc - 1 > MAX_PROBE_ARGS) {
177862306a36Sopenharmony_ci		semantic_error("Too many probe arguments (%d).\n", argc - 1);
177962306a36Sopenharmony_ci		ret = -ERANGE;
178062306a36Sopenharmony_ci		goto out;
178162306a36Sopenharmony_ci	}
178262306a36Sopenharmony_ci	/* Parse probe point */
178362306a36Sopenharmony_ci	ret = parse_perf_probe_point(argv[0], pev);
178462306a36Sopenharmony_ci	if (ret < 0)
178562306a36Sopenharmony_ci		goto out;
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci	/* Generate event name if needed */
178862306a36Sopenharmony_ci	if (!pev->event && pev->point.function && pev->point.line
178962306a36Sopenharmony_ci			&& !pev->point.lazy_line && !pev->point.offset) {
179062306a36Sopenharmony_ci		if (asprintf(&pev->event, "%s_L%d", pev->point.function,
179162306a36Sopenharmony_ci			pev->point.line) < 0) {
179262306a36Sopenharmony_ci			ret = -ENOMEM;
179362306a36Sopenharmony_ci			goto out;
179462306a36Sopenharmony_ci		}
179562306a36Sopenharmony_ci	}
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	/* Copy arguments and ensure return probe has no C argument */
179862306a36Sopenharmony_ci	pev->nargs = argc - 1;
179962306a36Sopenharmony_ci	pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
180062306a36Sopenharmony_ci	if (pev->args == NULL) {
180162306a36Sopenharmony_ci		ret = -ENOMEM;
180262306a36Sopenharmony_ci		goto out;
180362306a36Sopenharmony_ci	}
180462306a36Sopenharmony_ci	for (i = 0; i < pev->nargs && ret >= 0; i++) {
180562306a36Sopenharmony_ci		ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]);
180662306a36Sopenharmony_ci		if (ret >= 0 &&
180762306a36Sopenharmony_ci		    is_c_varname(pev->args[i].var) && pev->point.retprobe) {
180862306a36Sopenharmony_ci			semantic_error("You can't specify local variable for"
180962306a36Sopenharmony_ci				       " kretprobe.\n");
181062306a36Sopenharmony_ci			ret = -EINVAL;
181162306a36Sopenharmony_ci		}
181262306a36Sopenharmony_ci	}
181362306a36Sopenharmony_ciout:
181462306a36Sopenharmony_ci	argv_free(argv);
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	return ret;
181762306a36Sopenharmony_ci}
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci/* Returns true if *any* ARG is either C variable, $params or $vars. */
182062306a36Sopenharmony_cibool perf_probe_with_var(struct perf_probe_event *pev)
182162306a36Sopenharmony_ci{
182262306a36Sopenharmony_ci	int i = 0;
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	for (i = 0; i < pev->nargs; i++)
182562306a36Sopenharmony_ci		if (is_c_varname(pev->args[i].var)              ||
182662306a36Sopenharmony_ci		    !strcmp(pev->args[i].var, PROBE_ARG_PARAMS) ||
182762306a36Sopenharmony_ci		    !strcmp(pev->args[i].var, PROBE_ARG_VARS))
182862306a36Sopenharmony_ci			return true;
182962306a36Sopenharmony_ci	return false;
183062306a36Sopenharmony_ci}
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci/* Return true if this perf_probe_event requires debuginfo */
183362306a36Sopenharmony_cibool perf_probe_event_need_dwarf(struct perf_probe_event *pev)
183462306a36Sopenharmony_ci{
183562306a36Sopenharmony_ci	if (pev->point.file || pev->point.line || pev->point.lazy_line)
183662306a36Sopenharmony_ci		return true;
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	if (perf_probe_with_var(pev))
183962306a36Sopenharmony_ci		return true;
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	return false;
184262306a36Sopenharmony_ci}
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci/* Parse probe_events event into struct probe_point */
184562306a36Sopenharmony_ciint parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev)
184662306a36Sopenharmony_ci{
184762306a36Sopenharmony_ci	struct probe_trace_point *tp = &tev->point;
184862306a36Sopenharmony_ci	char pr;
184962306a36Sopenharmony_ci	char *p;
185062306a36Sopenharmony_ci	char *argv0_str = NULL, *fmt, *fmt1_str, *fmt2_str, *fmt3_str;
185162306a36Sopenharmony_ci	int ret, i, argc;
185262306a36Sopenharmony_ci	char **argv;
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci	pr_debug("Parsing probe_events: %s\n", cmd);
185562306a36Sopenharmony_ci	argv = argv_split(cmd, &argc);
185662306a36Sopenharmony_ci	if (!argv) {
185762306a36Sopenharmony_ci		pr_debug("Failed to split arguments.\n");
185862306a36Sopenharmony_ci		return -ENOMEM;
185962306a36Sopenharmony_ci	}
186062306a36Sopenharmony_ci	if (argc < 2) {
186162306a36Sopenharmony_ci		semantic_error("Too few probe arguments.\n");
186262306a36Sopenharmony_ci		ret = -ERANGE;
186362306a36Sopenharmony_ci		goto out;
186462306a36Sopenharmony_ci	}
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	/* Scan event and group name. */
186762306a36Sopenharmony_ci	argv0_str = strdup(argv[0]);
186862306a36Sopenharmony_ci	if (argv0_str == NULL) {
186962306a36Sopenharmony_ci		ret = -ENOMEM;
187062306a36Sopenharmony_ci		goto out;
187162306a36Sopenharmony_ci	}
187262306a36Sopenharmony_ci	fmt1_str = strtok_r(argv0_str, ":", &fmt);
187362306a36Sopenharmony_ci	fmt2_str = strtok_r(NULL, "/", &fmt);
187462306a36Sopenharmony_ci	fmt3_str = strtok_r(NULL, " \t", &fmt);
187562306a36Sopenharmony_ci	if (fmt1_str == NULL || fmt2_str == NULL || fmt3_str == NULL) {
187662306a36Sopenharmony_ci		semantic_error("Failed to parse event name: %s\n", argv[0]);
187762306a36Sopenharmony_ci		ret = -EINVAL;
187862306a36Sopenharmony_ci		goto out;
187962306a36Sopenharmony_ci	}
188062306a36Sopenharmony_ci	pr = fmt1_str[0];
188162306a36Sopenharmony_ci	tev->group = strdup(fmt2_str);
188262306a36Sopenharmony_ci	tev->event = strdup(fmt3_str);
188362306a36Sopenharmony_ci	if (tev->group == NULL || tev->event == NULL) {
188462306a36Sopenharmony_ci		ret = -ENOMEM;
188562306a36Sopenharmony_ci		goto out;
188662306a36Sopenharmony_ci	}
188762306a36Sopenharmony_ci	pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr);
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	tp->retprobe = (pr == 'r');
189062306a36Sopenharmony_ci
189162306a36Sopenharmony_ci	/* Scan module name(if there), function name and offset */
189262306a36Sopenharmony_ci	p = strchr(argv[1], ':');
189362306a36Sopenharmony_ci	if (p) {
189462306a36Sopenharmony_ci		tp->module = strndup(argv[1], p - argv[1]);
189562306a36Sopenharmony_ci		if (!tp->module) {
189662306a36Sopenharmony_ci			ret = -ENOMEM;
189762306a36Sopenharmony_ci			goto out;
189862306a36Sopenharmony_ci		}
189962306a36Sopenharmony_ci		tev->uprobes = (tp->module[0] == '/');
190062306a36Sopenharmony_ci		p++;
190162306a36Sopenharmony_ci	} else
190262306a36Sopenharmony_ci		p = argv[1];
190362306a36Sopenharmony_ci	fmt1_str = strtok_r(p, "+", &fmt);
190462306a36Sopenharmony_ci	/* only the address started with 0x */
190562306a36Sopenharmony_ci	if (fmt1_str[0] == '0')	{
190662306a36Sopenharmony_ci		/*
190762306a36Sopenharmony_ci		 * Fix a special case:
190862306a36Sopenharmony_ci		 * if address == 0, kernel reports something like:
190962306a36Sopenharmony_ci		 * p:probe_libc/abs_0 /lib/libc-2.18.so:0x          (null) arg1=%ax
191062306a36Sopenharmony_ci		 * Newer kernel may fix that, but we want to
191162306a36Sopenharmony_ci		 * support old kernel also.
191262306a36Sopenharmony_ci		 */
191362306a36Sopenharmony_ci		if (strcmp(fmt1_str, "0x") == 0) {
191462306a36Sopenharmony_ci			if (!argv[2] || strcmp(argv[2], "(null)")) {
191562306a36Sopenharmony_ci				ret = -EINVAL;
191662306a36Sopenharmony_ci				goto out;
191762306a36Sopenharmony_ci			}
191862306a36Sopenharmony_ci			tp->address = 0;
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci			free(argv[2]);
192162306a36Sopenharmony_ci			for (i = 2; argv[i + 1] != NULL; i++)
192262306a36Sopenharmony_ci				argv[i] = argv[i + 1];
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci			argv[i] = NULL;
192562306a36Sopenharmony_ci			argc -= 1;
192662306a36Sopenharmony_ci		} else
192762306a36Sopenharmony_ci			tp->address = strtoull(fmt1_str, NULL, 0);
192862306a36Sopenharmony_ci	} else {
192962306a36Sopenharmony_ci		/* Only the symbol-based probe has offset */
193062306a36Sopenharmony_ci		tp->symbol = strdup(fmt1_str);
193162306a36Sopenharmony_ci		if (tp->symbol == NULL) {
193262306a36Sopenharmony_ci			ret = -ENOMEM;
193362306a36Sopenharmony_ci			goto out;
193462306a36Sopenharmony_ci		}
193562306a36Sopenharmony_ci		fmt2_str = strtok_r(NULL, "", &fmt);
193662306a36Sopenharmony_ci		if (fmt2_str == NULL)
193762306a36Sopenharmony_ci			tp->offset = 0;
193862306a36Sopenharmony_ci		else
193962306a36Sopenharmony_ci			tp->offset = strtoul(fmt2_str, NULL, 10);
194062306a36Sopenharmony_ci	}
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	if (tev->uprobes) {
194362306a36Sopenharmony_ci		fmt2_str = strchr(p, '(');
194462306a36Sopenharmony_ci		if (fmt2_str)
194562306a36Sopenharmony_ci			tp->ref_ctr_offset = strtoul(fmt2_str + 1, NULL, 0);
194662306a36Sopenharmony_ci	}
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	tev->nargs = argc - 2;
194962306a36Sopenharmony_ci	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
195062306a36Sopenharmony_ci	if (tev->args == NULL) {
195162306a36Sopenharmony_ci		ret = -ENOMEM;
195262306a36Sopenharmony_ci		goto out;
195362306a36Sopenharmony_ci	}
195462306a36Sopenharmony_ci	for (i = 0; i < tev->nargs; i++) {
195562306a36Sopenharmony_ci		p = strchr(argv[i + 2], '=');
195662306a36Sopenharmony_ci		if (p)	/* We don't need which register is assigned. */
195762306a36Sopenharmony_ci			*p++ = '\0';
195862306a36Sopenharmony_ci		else
195962306a36Sopenharmony_ci			p = argv[i + 2];
196062306a36Sopenharmony_ci		tev->args[i].name = strdup(argv[i + 2]);
196162306a36Sopenharmony_ci		/* TODO: parse regs and offset */
196262306a36Sopenharmony_ci		tev->args[i].value = strdup(p);
196362306a36Sopenharmony_ci		if (tev->args[i].name == NULL || tev->args[i].value == NULL) {
196462306a36Sopenharmony_ci			ret = -ENOMEM;
196562306a36Sopenharmony_ci			goto out;
196662306a36Sopenharmony_ci		}
196762306a36Sopenharmony_ci	}
196862306a36Sopenharmony_ci	ret = 0;
196962306a36Sopenharmony_ciout:
197062306a36Sopenharmony_ci	free(argv0_str);
197162306a36Sopenharmony_ci	argv_free(argv);
197262306a36Sopenharmony_ci	return ret;
197362306a36Sopenharmony_ci}
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci/* Compose only probe arg */
197662306a36Sopenharmony_cichar *synthesize_perf_probe_arg(struct perf_probe_arg *pa)
197762306a36Sopenharmony_ci{
197862306a36Sopenharmony_ci	struct perf_probe_arg_field *field = pa->field;
197962306a36Sopenharmony_ci	struct strbuf buf;
198062306a36Sopenharmony_ci	char *ret = NULL;
198162306a36Sopenharmony_ci	int err;
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	if (strbuf_init(&buf, 64) < 0)
198462306a36Sopenharmony_ci		return NULL;
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci	if (pa->name && pa->var)
198762306a36Sopenharmony_ci		err = strbuf_addf(&buf, "%s=%s", pa->name, pa->var);
198862306a36Sopenharmony_ci	else
198962306a36Sopenharmony_ci		err = strbuf_addstr(&buf, pa->name ?: pa->var);
199062306a36Sopenharmony_ci	if (err)
199162306a36Sopenharmony_ci		goto out;
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	while (field) {
199462306a36Sopenharmony_ci		if (field->name[0] == '[')
199562306a36Sopenharmony_ci			err = strbuf_addstr(&buf, field->name);
199662306a36Sopenharmony_ci		else
199762306a36Sopenharmony_ci			err = strbuf_addf(&buf, "%s%s", field->ref ? "->" : ".",
199862306a36Sopenharmony_ci					  field->name);
199962306a36Sopenharmony_ci		field = field->next;
200062306a36Sopenharmony_ci		if (err)
200162306a36Sopenharmony_ci			goto out;
200262306a36Sopenharmony_ci	}
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	if (pa->type)
200562306a36Sopenharmony_ci		if (strbuf_addf(&buf, ":%s", pa->type) < 0)
200662306a36Sopenharmony_ci			goto out;
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	ret = strbuf_detach(&buf, NULL);
200962306a36Sopenharmony_ciout:
201062306a36Sopenharmony_ci	strbuf_release(&buf);
201162306a36Sopenharmony_ci	return ret;
201262306a36Sopenharmony_ci}
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci/* Compose only probe point (not argument) */
201562306a36Sopenharmony_cistatic char *synthesize_perf_probe_point(struct perf_probe_point *pp)
201662306a36Sopenharmony_ci{
201762306a36Sopenharmony_ci	struct strbuf buf;
201862306a36Sopenharmony_ci	char *tmp, *ret = NULL;
201962306a36Sopenharmony_ci	int len, err = 0;
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci	if (strbuf_init(&buf, 64) < 0)
202262306a36Sopenharmony_ci		return NULL;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	if (pp->function) {
202562306a36Sopenharmony_ci		if (strbuf_addstr(&buf, pp->function) < 0)
202662306a36Sopenharmony_ci			goto out;
202762306a36Sopenharmony_ci		if (pp->offset)
202862306a36Sopenharmony_ci			err = strbuf_addf(&buf, "+%lu", pp->offset);
202962306a36Sopenharmony_ci		else if (pp->line)
203062306a36Sopenharmony_ci			err = strbuf_addf(&buf, ":%d", pp->line);
203162306a36Sopenharmony_ci		else if (pp->retprobe)
203262306a36Sopenharmony_ci			err = strbuf_addstr(&buf, "%return");
203362306a36Sopenharmony_ci		if (err)
203462306a36Sopenharmony_ci			goto out;
203562306a36Sopenharmony_ci	}
203662306a36Sopenharmony_ci	if (pp->file) {
203762306a36Sopenharmony_ci		tmp = pp->file;
203862306a36Sopenharmony_ci		len = strlen(tmp);
203962306a36Sopenharmony_ci		if (len > 30) {
204062306a36Sopenharmony_ci			tmp = strchr(pp->file + len - 30, '/');
204162306a36Sopenharmony_ci			tmp = tmp ? tmp + 1 : pp->file + len - 30;
204262306a36Sopenharmony_ci		}
204362306a36Sopenharmony_ci		err = strbuf_addf(&buf, "@%s", tmp);
204462306a36Sopenharmony_ci		if (!err && !pp->function && pp->line)
204562306a36Sopenharmony_ci			err = strbuf_addf(&buf, ":%d", pp->line);
204662306a36Sopenharmony_ci	}
204762306a36Sopenharmony_ci	if (!err)
204862306a36Sopenharmony_ci		ret = strbuf_detach(&buf, NULL);
204962306a36Sopenharmony_ciout:
205062306a36Sopenharmony_ci	strbuf_release(&buf);
205162306a36Sopenharmony_ci	return ret;
205262306a36Sopenharmony_ci}
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_cichar *synthesize_perf_probe_command(struct perf_probe_event *pev)
205562306a36Sopenharmony_ci{
205662306a36Sopenharmony_ci	struct strbuf buf;
205762306a36Sopenharmony_ci	char *tmp, *ret = NULL;
205862306a36Sopenharmony_ci	int i;
205962306a36Sopenharmony_ci
206062306a36Sopenharmony_ci	if (strbuf_init(&buf, 64))
206162306a36Sopenharmony_ci		return NULL;
206262306a36Sopenharmony_ci	if (pev->event)
206362306a36Sopenharmony_ci		if (strbuf_addf(&buf, "%s:%s=", pev->group ?: PERFPROBE_GROUP,
206462306a36Sopenharmony_ci				pev->event) < 0)
206562306a36Sopenharmony_ci			goto out;
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	tmp = synthesize_perf_probe_point(&pev->point);
206862306a36Sopenharmony_ci	if (!tmp || strbuf_addstr(&buf, tmp) < 0) {
206962306a36Sopenharmony_ci		free(tmp);
207062306a36Sopenharmony_ci		goto out;
207162306a36Sopenharmony_ci	}
207262306a36Sopenharmony_ci	free(tmp);
207362306a36Sopenharmony_ci
207462306a36Sopenharmony_ci	for (i = 0; i < pev->nargs; i++) {
207562306a36Sopenharmony_ci		tmp = synthesize_perf_probe_arg(pev->args + i);
207662306a36Sopenharmony_ci		if (!tmp || strbuf_addf(&buf, " %s", tmp) < 0) {
207762306a36Sopenharmony_ci			free(tmp);
207862306a36Sopenharmony_ci			goto out;
207962306a36Sopenharmony_ci		}
208062306a36Sopenharmony_ci		free(tmp);
208162306a36Sopenharmony_ci	}
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci	ret = strbuf_detach(&buf, NULL);
208462306a36Sopenharmony_ciout:
208562306a36Sopenharmony_ci	strbuf_release(&buf);
208662306a36Sopenharmony_ci	return ret;
208762306a36Sopenharmony_ci}
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_cistatic int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref,
209062306a36Sopenharmony_ci					    struct strbuf *buf, int depth)
209162306a36Sopenharmony_ci{
209262306a36Sopenharmony_ci	int err;
209362306a36Sopenharmony_ci	if (ref->next) {
209462306a36Sopenharmony_ci		depth = __synthesize_probe_trace_arg_ref(ref->next, buf,
209562306a36Sopenharmony_ci							 depth + 1);
209662306a36Sopenharmony_ci		if (depth < 0)
209762306a36Sopenharmony_ci			return depth;
209862306a36Sopenharmony_ci	}
209962306a36Sopenharmony_ci	if (ref->user_access)
210062306a36Sopenharmony_ci		err = strbuf_addf(buf, "%s%ld(", "+u", ref->offset);
210162306a36Sopenharmony_ci	else
210262306a36Sopenharmony_ci		err = strbuf_addf(buf, "%+ld(", ref->offset);
210362306a36Sopenharmony_ci	return (err < 0) ? err : depth;
210462306a36Sopenharmony_ci}
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_cistatic int synthesize_probe_trace_arg(struct probe_trace_arg *arg,
210762306a36Sopenharmony_ci				      struct strbuf *buf)
210862306a36Sopenharmony_ci{
210962306a36Sopenharmony_ci	struct probe_trace_arg_ref *ref = arg->ref;
211062306a36Sopenharmony_ci	int depth = 0, err;
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	/* Argument name or separator */
211362306a36Sopenharmony_ci	if (arg->name)
211462306a36Sopenharmony_ci		err = strbuf_addf(buf, " %s=", arg->name);
211562306a36Sopenharmony_ci	else
211662306a36Sopenharmony_ci		err = strbuf_addch(buf, ' ');
211762306a36Sopenharmony_ci	if (err)
211862306a36Sopenharmony_ci		return err;
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	/* Special case: @XXX */
212162306a36Sopenharmony_ci	if (arg->value[0] == '@' && arg->ref)
212262306a36Sopenharmony_ci			ref = ref->next;
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_ci	/* Dereferencing arguments */
212562306a36Sopenharmony_ci	if (ref) {
212662306a36Sopenharmony_ci		depth = __synthesize_probe_trace_arg_ref(ref, buf, 1);
212762306a36Sopenharmony_ci		if (depth < 0)
212862306a36Sopenharmony_ci			return depth;
212962306a36Sopenharmony_ci	}
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ci	/* Print argument value */
213262306a36Sopenharmony_ci	if (arg->value[0] == '@' && arg->ref)
213362306a36Sopenharmony_ci		err = strbuf_addf(buf, "%s%+ld", arg->value, arg->ref->offset);
213462306a36Sopenharmony_ci	else
213562306a36Sopenharmony_ci		err = strbuf_addstr(buf, arg->value);
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	/* Closing */
213862306a36Sopenharmony_ci	while (!err && depth--)
213962306a36Sopenharmony_ci		err = strbuf_addch(buf, ')');
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	/* Print argument type */
214262306a36Sopenharmony_ci	if (!err && arg->type)
214362306a36Sopenharmony_ci		err = strbuf_addf(buf, ":%s", arg->type);
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	return err;
214662306a36Sopenharmony_ci}
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_cistatic int
214962306a36Sopenharmony_cisynthesize_probe_trace_args(struct probe_trace_event *tev, struct strbuf *buf)
215062306a36Sopenharmony_ci{
215162306a36Sopenharmony_ci	int i, ret = 0;
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	for (i = 0; i < tev->nargs && ret >= 0; i++)
215462306a36Sopenharmony_ci		ret = synthesize_probe_trace_arg(&tev->args[i], buf);
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ci	return ret;
215762306a36Sopenharmony_ci}
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_cistatic int
216062306a36Sopenharmony_cisynthesize_uprobe_trace_def(struct probe_trace_point *tp, struct strbuf *buf)
216162306a36Sopenharmony_ci{
216262306a36Sopenharmony_ci	int err;
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	/* Uprobes must have tp->module */
216562306a36Sopenharmony_ci	if (!tp->module)
216662306a36Sopenharmony_ci		return -EINVAL;
216762306a36Sopenharmony_ci	/*
216862306a36Sopenharmony_ci	 * If tp->address == 0, then this point must be a
216962306a36Sopenharmony_ci	 * absolute address uprobe.
217062306a36Sopenharmony_ci	 * try_to_find_absolute_address() should have made
217162306a36Sopenharmony_ci	 * tp->symbol to "0x0".
217262306a36Sopenharmony_ci	 */
217362306a36Sopenharmony_ci	if (!tp->address && (!tp->symbol || strcmp(tp->symbol, "0x0")))
217462306a36Sopenharmony_ci		return -EINVAL;
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	/* Use the tp->address for uprobes */
217762306a36Sopenharmony_ci	err = strbuf_addf(buf, "%s:0x%" PRIx64, tp->module, tp->address);
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	if (err >= 0 && tp->ref_ctr_offset) {
218062306a36Sopenharmony_ci		if (!uprobe_ref_ctr_is_supported())
218162306a36Sopenharmony_ci			return -EINVAL;
218262306a36Sopenharmony_ci		err = strbuf_addf(buf, "(0x%lx)", tp->ref_ctr_offset);
218362306a36Sopenharmony_ci	}
218462306a36Sopenharmony_ci	return err >= 0 ? 0 : err;
218562306a36Sopenharmony_ci}
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_cistatic int
218862306a36Sopenharmony_cisynthesize_kprobe_trace_def(struct probe_trace_point *tp, struct strbuf *buf)
218962306a36Sopenharmony_ci{
219062306a36Sopenharmony_ci	if (!strncmp(tp->symbol, "0x", 2)) {
219162306a36Sopenharmony_ci		/* Absolute address. See try_to_find_absolute_address() */
219262306a36Sopenharmony_ci		return strbuf_addf(buf, "%s%s0x%" PRIx64, tp->module ?: "",
219362306a36Sopenharmony_ci				  tp->module ? ":" : "", tp->address);
219462306a36Sopenharmony_ci	} else {
219562306a36Sopenharmony_ci		return strbuf_addf(buf, "%s%s%s+%lu", tp->module ?: "",
219662306a36Sopenharmony_ci				tp->module ? ":" : "", tp->symbol, tp->offset);
219762306a36Sopenharmony_ci	}
219862306a36Sopenharmony_ci}
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_cichar *synthesize_probe_trace_command(struct probe_trace_event *tev)
220162306a36Sopenharmony_ci{
220262306a36Sopenharmony_ci	struct probe_trace_point *tp = &tev->point;
220362306a36Sopenharmony_ci	struct strbuf buf;
220462306a36Sopenharmony_ci	char *ret = NULL;
220562306a36Sopenharmony_ci	int err;
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	if (strbuf_init(&buf, 32) < 0)
220862306a36Sopenharmony_ci		return NULL;
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_ci	if (strbuf_addf(&buf, "%c:%s/%s ", tp->retprobe ? 'r' : 'p',
221162306a36Sopenharmony_ci			tev->group, tev->event) < 0)
221262306a36Sopenharmony_ci		goto error;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	if (tev->uprobes)
221562306a36Sopenharmony_ci		err = synthesize_uprobe_trace_def(tp, &buf);
221662306a36Sopenharmony_ci	else
221762306a36Sopenharmony_ci		err = synthesize_kprobe_trace_def(tp, &buf);
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	if (err >= 0)
222062306a36Sopenharmony_ci		err = synthesize_probe_trace_args(tev, &buf);
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	if (err >= 0)
222362306a36Sopenharmony_ci		ret = strbuf_detach(&buf, NULL);
222462306a36Sopenharmony_cierror:
222562306a36Sopenharmony_ci	strbuf_release(&buf);
222662306a36Sopenharmony_ci	return ret;
222762306a36Sopenharmony_ci}
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_cistatic int find_perf_probe_point_from_map(struct probe_trace_point *tp,
223062306a36Sopenharmony_ci					  struct perf_probe_point *pp,
223162306a36Sopenharmony_ci					  bool is_kprobe)
223262306a36Sopenharmony_ci{
223362306a36Sopenharmony_ci	struct symbol *sym = NULL;
223462306a36Sopenharmony_ci	struct map *map = NULL;
223562306a36Sopenharmony_ci	u64 addr = tp->address;
223662306a36Sopenharmony_ci	int ret = -ENOENT;
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	if (!is_kprobe) {
223962306a36Sopenharmony_ci		map = dso__new_map(tp->module);
224062306a36Sopenharmony_ci		if (!map)
224162306a36Sopenharmony_ci			goto out;
224262306a36Sopenharmony_ci		sym = map__find_symbol(map, addr);
224362306a36Sopenharmony_ci	} else {
224462306a36Sopenharmony_ci		if (tp->symbol && !addr) {
224562306a36Sopenharmony_ci			if (kernel_get_symbol_address_by_name(tp->symbol,
224662306a36Sopenharmony_ci						&addr, true, false) < 0)
224762306a36Sopenharmony_ci				goto out;
224862306a36Sopenharmony_ci		}
224962306a36Sopenharmony_ci		if (addr) {
225062306a36Sopenharmony_ci			addr += tp->offset;
225162306a36Sopenharmony_ci			sym = machine__find_kernel_symbol(host_machine, addr, &map);
225262306a36Sopenharmony_ci		}
225362306a36Sopenharmony_ci	}
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci	if (!sym)
225662306a36Sopenharmony_ci		goto out;
225762306a36Sopenharmony_ci
225862306a36Sopenharmony_ci	pp->retprobe = tp->retprobe;
225962306a36Sopenharmony_ci	pp->offset = addr - map__unmap_ip(map, sym->start);
226062306a36Sopenharmony_ci	pp->function = strdup(sym->name);
226162306a36Sopenharmony_ci	ret = pp->function ? 0 : -ENOMEM;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ciout:
226462306a36Sopenharmony_ci	if (map && !is_kprobe) {
226562306a36Sopenharmony_ci		map__put(map);
226662306a36Sopenharmony_ci	}
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_ci	return ret;
226962306a36Sopenharmony_ci}
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_cistatic int convert_to_perf_probe_point(struct probe_trace_point *tp,
227262306a36Sopenharmony_ci				       struct perf_probe_point *pp,
227362306a36Sopenharmony_ci				       bool is_kprobe)
227462306a36Sopenharmony_ci{
227562306a36Sopenharmony_ci	char buf[128];
227662306a36Sopenharmony_ci	int ret;
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_ci	ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe);
227962306a36Sopenharmony_ci	if (!ret)
228062306a36Sopenharmony_ci		return 0;
228162306a36Sopenharmony_ci	ret = find_perf_probe_point_from_map(tp, pp, is_kprobe);
228262306a36Sopenharmony_ci	if (!ret)
228362306a36Sopenharmony_ci		return 0;
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci	pr_debug("Failed to find probe point from both of dwarf and map.\n");
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci	if (tp->symbol) {
228862306a36Sopenharmony_ci		pp->function = strdup(tp->symbol);
228962306a36Sopenharmony_ci		pp->offset = tp->offset;
229062306a36Sopenharmony_ci	} else {
229162306a36Sopenharmony_ci		ret = e_snprintf(buf, 128, "0x%" PRIx64, tp->address);
229262306a36Sopenharmony_ci		if (ret < 0)
229362306a36Sopenharmony_ci			return ret;
229462306a36Sopenharmony_ci		pp->function = strdup(buf);
229562306a36Sopenharmony_ci		pp->offset = 0;
229662306a36Sopenharmony_ci	}
229762306a36Sopenharmony_ci	if (pp->function == NULL)
229862306a36Sopenharmony_ci		return -ENOMEM;
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci	pp->retprobe = tp->retprobe;
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	return 0;
230362306a36Sopenharmony_ci}
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_cistatic int convert_to_perf_probe_event(struct probe_trace_event *tev,
230662306a36Sopenharmony_ci			       struct perf_probe_event *pev, bool is_kprobe)
230762306a36Sopenharmony_ci{
230862306a36Sopenharmony_ci	struct strbuf buf = STRBUF_INIT;
230962306a36Sopenharmony_ci	int i, ret;
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	/* Convert event/group name */
231262306a36Sopenharmony_ci	pev->event = strdup(tev->event);
231362306a36Sopenharmony_ci	pev->group = strdup(tev->group);
231462306a36Sopenharmony_ci	if (pev->event == NULL || pev->group == NULL)
231562306a36Sopenharmony_ci		return -ENOMEM;
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci	/* Convert trace_point to probe_point */
231862306a36Sopenharmony_ci	ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe);
231962306a36Sopenharmony_ci	if (ret < 0)
232062306a36Sopenharmony_ci		return ret;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	/* Convert trace_arg to probe_arg */
232362306a36Sopenharmony_ci	pev->nargs = tev->nargs;
232462306a36Sopenharmony_ci	pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs);
232562306a36Sopenharmony_ci	if (pev->args == NULL)
232662306a36Sopenharmony_ci		return -ENOMEM;
232762306a36Sopenharmony_ci	for (i = 0; i < tev->nargs && ret >= 0; i++) {
232862306a36Sopenharmony_ci		if (tev->args[i].name)
232962306a36Sopenharmony_ci			pev->args[i].name = strdup(tev->args[i].name);
233062306a36Sopenharmony_ci		else {
233162306a36Sopenharmony_ci			if ((ret = strbuf_init(&buf, 32)) < 0)
233262306a36Sopenharmony_ci				goto error;
233362306a36Sopenharmony_ci			ret = synthesize_probe_trace_arg(&tev->args[i], &buf);
233462306a36Sopenharmony_ci			pev->args[i].name = strbuf_detach(&buf, NULL);
233562306a36Sopenharmony_ci		}
233662306a36Sopenharmony_ci		if (pev->args[i].name == NULL && ret >= 0)
233762306a36Sopenharmony_ci			ret = -ENOMEM;
233862306a36Sopenharmony_ci	}
233962306a36Sopenharmony_cierror:
234062306a36Sopenharmony_ci	if (ret < 0)
234162306a36Sopenharmony_ci		clear_perf_probe_event(pev);
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	return ret;
234462306a36Sopenharmony_ci}
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_civoid clear_perf_probe_event(struct perf_probe_event *pev)
234762306a36Sopenharmony_ci{
234862306a36Sopenharmony_ci	struct perf_probe_arg_field *field, *next;
234962306a36Sopenharmony_ci	int i;
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	zfree(&pev->event);
235262306a36Sopenharmony_ci	zfree(&pev->group);
235362306a36Sopenharmony_ci	zfree(&pev->target);
235462306a36Sopenharmony_ci	clear_perf_probe_point(&pev->point);
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	for (i = 0; i < pev->nargs; i++) {
235762306a36Sopenharmony_ci		zfree(&pev->args[i].name);
235862306a36Sopenharmony_ci		zfree(&pev->args[i].var);
235962306a36Sopenharmony_ci		zfree(&pev->args[i].type);
236062306a36Sopenharmony_ci		field = pev->args[i].field;
236162306a36Sopenharmony_ci		while (field) {
236262306a36Sopenharmony_ci			next = field->next;
236362306a36Sopenharmony_ci			zfree(&field->name);
236462306a36Sopenharmony_ci			free(field);
236562306a36Sopenharmony_ci			field = next;
236662306a36Sopenharmony_ci		}
236762306a36Sopenharmony_ci	}
236862306a36Sopenharmony_ci	pev->nargs = 0;
236962306a36Sopenharmony_ci	zfree(&pev->args);
237062306a36Sopenharmony_ci}
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci#define strdup_or_goto(str, label)	\
237362306a36Sopenharmony_ci({ char *__p = NULL; if (str && !(__p = strdup(str))) goto label; __p; })
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_cistatic int perf_probe_point__copy(struct perf_probe_point *dst,
237662306a36Sopenharmony_ci				  struct perf_probe_point *src)
237762306a36Sopenharmony_ci{
237862306a36Sopenharmony_ci	dst->file = strdup_or_goto(src->file, out_err);
237962306a36Sopenharmony_ci	dst->function = strdup_or_goto(src->function, out_err);
238062306a36Sopenharmony_ci	dst->lazy_line = strdup_or_goto(src->lazy_line, out_err);
238162306a36Sopenharmony_ci	dst->line = src->line;
238262306a36Sopenharmony_ci	dst->retprobe = src->retprobe;
238362306a36Sopenharmony_ci	dst->offset = src->offset;
238462306a36Sopenharmony_ci	return 0;
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ciout_err:
238762306a36Sopenharmony_ci	clear_perf_probe_point(dst);
238862306a36Sopenharmony_ci	return -ENOMEM;
238962306a36Sopenharmony_ci}
239062306a36Sopenharmony_ci
239162306a36Sopenharmony_cistatic int perf_probe_arg__copy(struct perf_probe_arg *dst,
239262306a36Sopenharmony_ci				struct perf_probe_arg *src)
239362306a36Sopenharmony_ci{
239462306a36Sopenharmony_ci	struct perf_probe_arg_field *field, **ppfield;
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_ci	dst->name = strdup_or_goto(src->name, out_err);
239762306a36Sopenharmony_ci	dst->var = strdup_or_goto(src->var, out_err);
239862306a36Sopenharmony_ci	dst->type = strdup_or_goto(src->type, out_err);
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci	field = src->field;
240162306a36Sopenharmony_ci	ppfield = &(dst->field);
240262306a36Sopenharmony_ci	while (field) {
240362306a36Sopenharmony_ci		*ppfield = zalloc(sizeof(*field));
240462306a36Sopenharmony_ci		if (!*ppfield)
240562306a36Sopenharmony_ci			goto out_err;
240662306a36Sopenharmony_ci		(*ppfield)->name = strdup_or_goto(field->name, out_err);
240762306a36Sopenharmony_ci		(*ppfield)->index = field->index;
240862306a36Sopenharmony_ci		(*ppfield)->ref = field->ref;
240962306a36Sopenharmony_ci		field = field->next;
241062306a36Sopenharmony_ci		ppfield = &((*ppfield)->next);
241162306a36Sopenharmony_ci	}
241262306a36Sopenharmony_ci	return 0;
241362306a36Sopenharmony_ciout_err:
241462306a36Sopenharmony_ci	return -ENOMEM;
241562306a36Sopenharmony_ci}
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_ciint perf_probe_event__copy(struct perf_probe_event *dst,
241862306a36Sopenharmony_ci			   struct perf_probe_event *src)
241962306a36Sopenharmony_ci{
242062306a36Sopenharmony_ci	int i;
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci	dst->event = strdup_or_goto(src->event, out_err);
242362306a36Sopenharmony_ci	dst->group = strdup_or_goto(src->group, out_err);
242462306a36Sopenharmony_ci	dst->target = strdup_or_goto(src->target, out_err);
242562306a36Sopenharmony_ci	dst->uprobes = src->uprobes;
242662306a36Sopenharmony_ci
242762306a36Sopenharmony_ci	if (perf_probe_point__copy(&dst->point, &src->point) < 0)
242862306a36Sopenharmony_ci		goto out_err;
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci	dst->args = zalloc(sizeof(struct perf_probe_arg) * src->nargs);
243162306a36Sopenharmony_ci	if (!dst->args)
243262306a36Sopenharmony_ci		goto out_err;
243362306a36Sopenharmony_ci	dst->nargs = src->nargs;
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	for (i = 0; i < src->nargs; i++)
243662306a36Sopenharmony_ci		if (perf_probe_arg__copy(&dst->args[i], &src->args[i]) < 0)
243762306a36Sopenharmony_ci			goto out_err;
243862306a36Sopenharmony_ci	return 0;
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ciout_err:
244162306a36Sopenharmony_ci	clear_perf_probe_event(dst);
244262306a36Sopenharmony_ci	return -ENOMEM;
244362306a36Sopenharmony_ci}
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_civoid clear_probe_trace_event(struct probe_trace_event *tev)
244662306a36Sopenharmony_ci{
244762306a36Sopenharmony_ci	struct probe_trace_arg_ref *ref, *next;
244862306a36Sopenharmony_ci	int i;
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci	zfree(&tev->event);
245162306a36Sopenharmony_ci	zfree(&tev->group);
245262306a36Sopenharmony_ci	zfree(&tev->point.symbol);
245362306a36Sopenharmony_ci	zfree(&tev->point.realname);
245462306a36Sopenharmony_ci	zfree(&tev->point.module);
245562306a36Sopenharmony_ci	for (i = 0; i < tev->nargs; i++) {
245662306a36Sopenharmony_ci		zfree(&tev->args[i].name);
245762306a36Sopenharmony_ci		zfree(&tev->args[i].value);
245862306a36Sopenharmony_ci		zfree(&tev->args[i].type);
245962306a36Sopenharmony_ci		ref = tev->args[i].ref;
246062306a36Sopenharmony_ci		while (ref) {
246162306a36Sopenharmony_ci			next = ref->next;
246262306a36Sopenharmony_ci			free(ref);
246362306a36Sopenharmony_ci			ref = next;
246462306a36Sopenharmony_ci		}
246562306a36Sopenharmony_ci	}
246662306a36Sopenharmony_ci	zfree(&tev->args);
246762306a36Sopenharmony_ci	tev->nargs = 0;
246862306a36Sopenharmony_ci}
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_cistruct kprobe_blacklist_node {
247162306a36Sopenharmony_ci	struct list_head list;
247262306a36Sopenharmony_ci	u64 start;
247362306a36Sopenharmony_ci	u64 end;
247462306a36Sopenharmony_ci	char *symbol;
247562306a36Sopenharmony_ci};
247662306a36Sopenharmony_ci
247762306a36Sopenharmony_cistatic void kprobe_blacklist__delete(struct list_head *blacklist)
247862306a36Sopenharmony_ci{
247962306a36Sopenharmony_ci	struct kprobe_blacklist_node *node;
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ci	while (!list_empty(blacklist)) {
248262306a36Sopenharmony_ci		node = list_first_entry(blacklist,
248362306a36Sopenharmony_ci					struct kprobe_blacklist_node, list);
248462306a36Sopenharmony_ci		list_del_init(&node->list);
248562306a36Sopenharmony_ci		zfree(&node->symbol);
248662306a36Sopenharmony_ci		free(node);
248762306a36Sopenharmony_ci	}
248862306a36Sopenharmony_ci}
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_cistatic int kprobe_blacklist__load(struct list_head *blacklist)
249162306a36Sopenharmony_ci{
249262306a36Sopenharmony_ci	struct kprobe_blacklist_node *node;
249362306a36Sopenharmony_ci	const char *__debugfs = debugfs__mountpoint();
249462306a36Sopenharmony_ci	char buf[PATH_MAX], *p;
249562306a36Sopenharmony_ci	FILE *fp;
249662306a36Sopenharmony_ci	int ret;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	if (__debugfs == NULL)
249962306a36Sopenharmony_ci		return -ENOTSUP;
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci	ret = e_snprintf(buf, PATH_MAX, "%s/kprobes/blacklist", __debugfs);
250262306a36Sopenharmony_ci	if (ret < 0)
250362306a36Sopenharmony_ci		return ret;
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	fp = fopen(buf, "r");
250662306a36Sopenharmony_ci	if (!fp)
250762306a36Sopenharmony_ci		return -errno;
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci	ret = 0;
251062306a36Sopenharmony_ci	while (fgets(buf, PATH_MAX, fp)) {
251162306a36Sopenharmony_ci		node = zalloc(sizeof(*node));
251262306a36Sopenharmony_ci		if (!node) {
251362306a36Sopenharmony_ci			ret = -ENOMEM;
251462306a36Sopenharmony_ci			break;
251562306a36Sopenharmony_ci		}
251662306a36Sopenharmony_ci		INIT_LIST_HEAD(&node->list);
251762306a36Sopenharmony_ci		list_add_tail(&node->list, blacklist);
251862306a36Sopenharmony_ci		if (sscanf(buf, "0x%" PRIx64 "-0x%" PRIx64, &node->start, &node->end) != 2) {
251962306a36Sopenharmony_ci			ret = -EINVAL;
252062306a36Sopenharmony_ci			break;
252162306a36Sopenharmony_ci		}
252262306a36Sopenharmony_ci		p = strchr(buf, '\t');
252362306a36Sopenharmony_ci		if (p) {
252462306a36Sopenharmony_ci			p++;
252562306a36Sopenharmony_ci			if (p[strlen(p) - 1] == '\n')
252662306a36Sopenharmony_ci				p[strlen(p) - 1] = '\0';
252762306a36Sopenharmony_ci		} else
252862306a36Sopenharmony_ci			p = (char *)"unknown";
252962306a36Sopenharmony_ci		node->symbol = strdup(p);
253062306a36Sopenharmony_ci		if (!node->symbol) {
253162306a36Sopenharmony_ci			ret = -ENOMEM;
253262306a36Sopenharmony_ci			break;
253362306a36Sopenharmony_ci		}
253462306a36Sopenharmony_ci		pr_debug2("Blacklist: 0x%" PRIx64 "-0x%" PRIx64 ", %s\n",
253562306a36Sopenharmony_ci			  node->start, node->end, node->symbol);
253662306a36Sopenharmony_ci		ret++;
253762306a36Sopenharmony_ci	}
253862306a36Sopenharmony_ci	if (ret < 0)
253962306a36Sopenharmony_ci		kprobe_blacklist__delete(blacklist);
254062306a36Sopenharmony_ci	fclose(fp);
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	return ret;
254362306a36Sopenharmony_ci}
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_cistatic struct kprobe_blacklist_node *
254662306a36Sopenharmony_cikprobe_blacklist__find_by_address(struct list_head *blacklist, u64 address)
254762306a36Sopenharmony_ci{
254862306a36Sopenharmony_ci	struct kprobe_blacklist_node *node;
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	list_for_each_entry(node, blacklist, list) {
255162306a36Sopenharmony_ci		if (node->start <= address && address < node->end)
255262306a36Sopenharmony_ci			return node;
255362306a36Sopenharmony_ci	}
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	return NULL;
255662306a36Sopenharmony_ci}
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_cistatic LIST_HEAD(kprobe_blacklist);
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_cistatic void kprobe_blacklist__init(void)
256162306a36Sopenharmony_ci{
256262306a36Sopenharmony_ci	if (!list_empty(&kprobe_blacklist))
256362306a36Sopenharmony_ci		return;
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci	if (kprobe_blacklist__load(&kprobe_blacklist) < 0)
256662306a36Sopenharmony_ci		pr_debug("No kprobe blacklist support, ignored\n");
256762306a36Sopenharmony_ci}
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_cistatic void kprobe_blacklist__release(void)
257062306a36Sopenharmony_ci{
257162306a36Sopenharmony_ci	kprobe_blacklist__delete(&kprobe_blacklist);
257262306a36Sopenharmony_ci}
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_cistatic bool kprobe_blacklist__listed(u64 address)
257562306a36Sopenharmony_ci{
257662306a36Sopenharmony_ci	return !!kprobe_blacklist__find_by_address(&kprobe_blacklist, address);
257762306a36Sopenharmony_ci}
257862306a36Sopenharmony_ci
257962306a36Sopenharmony_cistatic int perf_probe_event__sprintf(const char *group, const char *event,
258062306a36Sopenharmony_ci				     struct perf_probe_event *pev,
258162306a36Sopenharmony_ci				     const char *module,
258262306a36Sopenharmony_ci				     struct strbuf *result)
258362306a36Sopenharmony_ci{
258462306a36Sopenharmony_ci	int i, ret;
258562306a36Sopenharmony_ci	char *buf;
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci	if (asprintf(&buf, "%s:%s", group, event) < 0)
258862306a36Sopenharmony_ci		return -errno;
258962306a36Sopenharmony_ci	ret = strbuf_addf(result, "  %-20s (on ", buf);
259062306a36Sopenharmony_ci	free(buf);
259162306a36Sopenharmony_ci	if (ret)
259262306a36Sopenharmony_ci		return ret;
259362306a36Sopenharmony_ci
259462306a36Sopenharmony_ci	/* Synthesize only event probe point */
259562306a36Sopenharmony_ci	buf = synthesize_perf_probe_point(&pev->point);
259662306a36Sopenharmony_ci	if (!buf)
259762306a36Sopenharmony_ci		return -ENOMEM;
259862306a36Sopenharmony_ci	ret = strbuf_addstr(result, buf);
259962306a36Sopenharmony_ci	free(buf);
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci	if (!ret && module)
260262306a36Sopenharmony_ci		ret = strbuf_addf(result, " in %s", module);
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	if (!ret && pev->nargs > 0) {
260562306a36Sopenharmony_ci		ret = strbuf_add(result, " with", 5);
260662306a36Sopenharmony_ci		for (i = 0; !ret && i < pev->nargs; i++) {
260762306a36Sopenharmony_ci			buf = synthesize_perf_probe_arg(&pev->args[i]);
260862306a36Sopenharmony_ci			if (!buf)
260962306a36Sopenharmony_ci				return -ENOMEM;
261062306a36Sopenharmony_ci			ret = strbuf_addf(result, " %s", buf);
261162306a36Sopenharmony_ci			free(buf);
261262306a36Sopenharmony_ci		}
261362306a36Sopenharmony_ci	}
261462306a36Sopenharmony_ci	if (!ret)
261562306a36Sopenharmony_ci		ret = strbuf_addch(result, ')');
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci	return ret;
261862306a36Sopenharmony_ci}
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci/* Show an event */
262162306a36Sopenharmony_ciint show_perf_probe_event(const char *group, const char *event,
262262306a36Sopenharmony_ci			  struct perf_probe_event *pev,
262362306a36Sopenharmony_ci			  const char *module, bool use_stdout)
262462306a36Sopenharmony_ci{
262562306a36Sopenharmony_ci	struct strbuf buf = STRBUF_INIT;
262662306a36Sopenharmony_ci	int ret;
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ci	ret = perf_probe_event__sprintf(group, event, pev, module, &buf);
262962306a36Sopenharmony_ci	if (ret >= 0) {
263062306a36Sopenharmony_ci		if (use_stdout)
263162306a36Sopenharmony_ci			printf("%s\n", buf.buf);
263262306a36Sopenharmony_ci		else
263362306a36Sopenharmony_ci			pr_info("%s\n", buf.buf);
263462306a36Sopenharmony_ci	}
263562306a36Sopenharmony_ci	strbuf_release(&buf);
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_ci	return ret;
263862306a36Sopenharmony_ci}
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_cistatic bool filter_probe_trace_event(struct probe_trace_event *tev,
264162306a36Sopenharmony_ci				     struct strfilter *filter)
264262306a36Sopenharmony_ci{
264362306a36Sopenharmony_ci	char tmp[128];
264462306a36Sopenharmony_ci
264562306a36Sopenharmony_ci	/* At first, check the event name itself */
264662306a36Sopenharmony_ci	if (strfilter__compare(filter, tev->event))
264762306a36Sopenharmony_ci		return true;
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_ci	/* Next, check the combination of name and group */
265062306a36Sopenharmony_ci	if (e_snprintf(tmp, 128, "%s:%s", tev->group, tev->event) < 0)
265162306a36Sopenharmony_ci		return false;
265262306a36Sopenharmony_ci	return strfilter__compare(filter, tmp);
265362306a36Sopenharmony_ci}
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_cistatic int __show_perf_probe_events(int fd, bool is_kprobe,
265662306a36Sopenharmony_ci				    struct strfilter *filter)
265762306a36Sopenharmony_ci{
265862306a36Sopenharmony_ci	int ret = 0;
265962306a36Sopenharmony_ci	struct probe_trace_event tev;
266062306a36Sopenharmony_ci	struct perf_probe_event pev;
266162306a36Sopenharmony_ci	struct strlist *rawlist;
266262306a36Sopenharmony_ci	struct str_node *ent;
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	memset(&tev, 0, sizeof(tev));
266562306a36Sopenharmony_ci	memset(&pev, 0, sizeof(pev));
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	rawlist = probe_file__get_rawlist(fd);
266862306a36Sopenharmony_ci	if (!rawlist)
266962306a36Sopenharmony_ci		return -ENOMEM;
267062306a36Sopenharmony_ci
267162306a36Sopenharmony_ci	strlist__for_each_entry(ent, rawlist) {
267262306a36Sopenharmony_ci		ret = parse_probe_trace_command(ent->s, &tev);
267362306a36Sopenharmony_ci		if (ret >= 0) {
267462306a36Sopenharmony_ci			if (!filter_probe_trace_event(&tev, filter))
267562306a36Sopenharmony_ci				goto next;
267662306a36Sopenharmony_ci			ret = convert_to_perf_probe_event(&tev, &pev,
267762306a36Sopenharmony_ci								is_kprobe);
267862306a36Sopenharmony_ci			if (ret < 0)
267962306a36Sopenharmony_ci				goto next;
268062306a36Sopenharmony_ci			ret = show_perf_probe_event(pev.group, pev.event,
268162306a36Sopenharmony_ci						    &pev, tev.point.module,
268262306a36Sopenharmony_ci						    true);
268362306a36Sopenharmony_ci		}
268462306a36Sopenharmony_cinext:
268562306a36Sopenharmony_ci		clear_perf_probe_event(&pev);
268662306a36Sopenharmony_ci		clear_probe_trace_event(&tev);
268762306a36Sopenharmony_ci		if (ret < 0)
268862306a36Sopenharmony_ci			break;
268962306a36Sopenharmony_ci	}
269062306a36Sopenharmony_ci	strlist__delete(rawlist);
269162306a36Sopenharmony_ci	/* Cleanup cached debuginfo if needed */
269262306a36Sopenharmony_ci	debuginfo_cache__exit();
269362306a36Sopenharmony_ci
269462306a36Sopenharmony_ci	return ret;
269562306a36Sopenharmony_ci}
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci/* List up current perf-probe events */
269862306a36Sopenharmony_ciint show_perf_probe_events(struct strfilter *filter)
269962306a36Sopenharmony_ci{
270062306a36Sopenharmony_ci	int kp_fd, up_fd, ret;
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci	setup_pager();
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_ci	if (probe_conf.cache)
270562306a36Sopenharmony_ci		return probe_cache__show_all_caches(filter);
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_ci	ret = init_probe_symbol_maps(false);
270862306a36Sopenharmony_ci	if (ret < 0)
270962306a36Sopenharmony_ci		return ret;
271062306a36Sopenharmony_ci
271162306a36Sopenharmony_ci	ret = probe_file__open_both(&kp_fd, &up_fd, 0);
271262306a36Sopenharmony_ci	if (ret < 0)
271362306a36Sopenharmony_ci		return ret;
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci	if (kp_fd >= 0)
271662306a36Sopenharmony_ci		ret = __show_perf_probe_events(kp_fd, true, filter);
271762306a36Sopenharmony_ci	if (up_fd >= 0 && ret >= 0)
271862306a36Sopenharmony_ci		ret = __show_perf_probe_events(up_fd, false, filter);
271962306a36Sopenharmony_ci	if (kp_fd > 0)
272062306a36Sopenharmony_ci		close(kp_fd);
272162306a36Sopenharmony_ci	if (up_fd > 0)
272262306a36Sopenharmony_ci		close(up_fd);
272362306a36Sopenharmony_ci	exit_probe_symbol_maps();
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci	return ret;
272662306a36Sopenharmony_ci}
272762306a36Sopenharmony_ci
272862306a36Sopenharmony_cistatic int get_new_event_name(char *buf, size_t len, const char *base,
272962306a36Sopenharmony_ci			      struct strlist *namelist, bool ret_event,
273062306a36Sopenharmony_ci			      bool allow_suffix)
273162306a36Sopenharmony_ci{
273262306a36Sopenharmony_ci	int i, ret;
273362306a36Sopenharmony_ci	char *p, *nbase;
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	if (*base == '.')
273662306a36Sopenharmony_ci		base++;
273762306a36Sopenharmony_ci	nbase = strdup(base);
273862306a36Sopenharmony_ci	if (!nbase)
273962306a36Sopenharmony_ci		return -ENOMEM;
274062306a36Sopenharmony_ci
274162306a36Sopenharmony_ci	/* Cut off the dot suffixes (e.g. .const, .isra) and version suffixes */
274262306a36Sopenharmony_ci	p = strpbrk(nbase, ".@");
274362306a36Sopenharmony_ci	if (p && p != nbase)
274462306a36Sopenharmony_ci		*p = '\0';
274562306a36Sopenharmony_ci
274662306a36Sopenharmony_ci	/* Try no suffix number */
274762306a36Sopenharmony_ci	ret = e_snprintf(buf, len, "%s%s", nbase, ret_event ? "__return" : "");
274862306a36Sopenharmony_ci	if (ret < 0) {
274962306a36Sopenharmony_ci		pr_debug("snprintf() failed: %d\n", ret);
275062306a36Sopenharmony_ci		goto out;
275162306a36Sopenharmony_ci	}
275262306a36Sopenharmony_ci	if (!strlist__has_entry(namelist, buf))
275362306a36Sopenharmony_ci		goto out;
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci	if (!allow_suffix) {
275662306a36Sopenharmony_ci		pr_warning("Error: event \"%s\" already exists.\n"
275762306a36Sopenharmony_ci			   " Hint: Remove existing event by 'perf probe -d'\n"
275862306a36Sopenharmony_ci			   "       or force duplicates by 'perf probe -f'\n"
275962306a36Sopenharmony_ci			   "       or set 'force=yes' in BPF source.\n",
276062306a36Sopenharmony_ci			   buf);
276162306a36Sopenharmony_ci		ret = -EEXIST;
276262306a36Sopenharmony_ci		goto out;
276362306a36Sopenharmony_ci	}
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci	/* Try to add suffix */
276662306a36Sopenharmony_ci	for (i = 1; i < MAX_EVENT_INDEX; i++) {
276762306a36Sopenharmony_ci		ret = e_snprintf(buf, len, "%s_%d", nbase, i);
276862306a36Sopenharmony_ci		if (ret < 0) {
276962306a36Sopenharmony_ci			pr_debug("snprintf() failed: %d\n", ret);
277062306a36Sopenharmony_ci			goto out;
277162306a36Sopenharmony_ci		}
277262306a36Sopenharmony_ci		if (!strlist__has_entry(namelist, buf))
277362306a36Sopenharmony_ci			break;
277462306a36Sopenharmony_ci	}
277562306a36Sopenharmony_ci	if (i == MAX_EVENT_INDEX) {
277662306a36Sopenharmony_ci		pr_warning("Too many events are on the same function.\n");
277762306a36Sopenharmony_ci		ret = -ERANGE;
277862306a36Sopenharmony_ci	}
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_ciout:
278162306a36Sopenharmony_ci	free(nbase);
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci	/* Final validation */
278462306a36Sopenharmony_ci	if (ret >= 0 && !is_c_func_name(buf)) {
278562306a36Sopenharmony_ci		pr_warning("Internal error: \"%s\" is an invalid event name.\n",
278662306a36Sopenharmony_ci			   buf);
278762306a36Sopenharmony_ci		ret = -EINVAL;
278862306a36Sopenharmony_ci	}
278962306a36Sopenharmony_ci
279062306a36Sopenharmony_ci	return ret;
279162306a36Sopenharmony_ci}
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci/* Warn if the current kernel's uprobe implementation is old */
279462306a36Sopenharmony_cistatic void warn_uprobe_event_compat(struct probe_trace_event *tev)
279562306a36Sopenharmony_ci{
279662306a36Sopenharmony_ci	int i;
279762306a36Sopenharmony_ci	char *buf = synthesize_probe_trace_command(tev);
279862306a36Sopenharmony_ci	struct probe_trace_point *tp = &tev->point;
279962306a36Sopenharmony_ci
280062306a36Sopenharmony_ci	if (tp->ref_ctr_offset && !uprobe_ref_ctr_is_supported()) {
280162306a36Sopenharmony_ci		pr_warning("A semaphore is associated with %s:%s and "
280262306a36Sopenharmony_ci			   "seems your kernel doesn't support it.\n",
280362306a36Sopenharmony_ci			   tev->group, tev->event);
280462306a36Sopenharmony_ci	}
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci	/* Old uprobe event doesn't support memory dereference */
280762306a36Sopenharmony_ci	if (!tev->uprobes || tev->nargs == 0 || !buf)
280862306a36Sopenharmony_ci		goto out;
280962306a36Sopenharmony_ci
281062306a36Sopenharmony_ci	for (i = 0; i < tev->nargs; i++) {
281162306a36Sopenharmony_ci		if (strchr(tev->args[i].value, '@')) {
281262306a36Sopenharmony_ci			pr_warning("%s accesses a variable by symbol name, but that is not supported for user application probe.\n",
281362306a36Sopenharmony_ci				   tev->args[i].value);
281462306a36Sopenharmony_ci			break;
281562306a36Sopenharmony_ci		}
281662306a36Sopenharmony_ci		if (strglobmatch(tev->args[i].value, "[$+-]*")) {
281762306a36Sopenharmony_ci			pr_warning("Please upgrade your kernel to at least 3.14 to have access to feature %s\n",
281862306a36Sopenharmony_ci				   tev->args[i].value);
281962306a36Sopenharmony_ci			break;
282062306a36Sopenharmony_ci		}
282162306a36Sopenharmony_ci	}
282262306a36Sopenharmony_ciout:
282362306a36Sopenharmony_ci	free(buf);
282462306a36Sopenharmony_ci}
282562306a36Sopenharmony_ci
282662306a36Sopenharmony_ci/* Set new name from original perf_probe_event and namelist */
282762306a36Sopenharmony_cistatic int probe_trace_event__set_name(struct probe_trace_event *tev,
282862306a36Sopenharmony_ci				       struct perf_probe_event *pev,
282962306a36Sopenharmony_ci				       struct strlist *namelist,
283062306a36Sopenharmony_ci				       bool allow_suffix)
283162306a36Sopenharmony_ci{
283262306a36Sopenharmony_ci	const char *event, *group;
283362306a36Sopenharmony_ci	char buf[64];
283462306a36Sopenharmony_ci	int ret;
283562306a36Sopenharmony_ci
283662306a36Sopenharmony_ci	/* If probe_event or trace_event already have the name, reuse it */
283762306a36Sopenharmony_ci	if (pev->event && !pev->sdt)
283862306a36Sopenharmony_ci		event = pev->event;
283962306a36Sopenharmony_ci	else if (tev->event)
284062306a36Sopenharmony_ci		event = tev->event;
284162306a36Sopenharmony_ci	else {
284262306a36Sopenharmony_ci		/* Or generate new one from probe point */
284362306a36Sopenharmony_ci		if (pev->point.function &&
284462306a36Sopenharmony_ci			(strncmp(pev->point.function, "0x", 2) != 0) &&
284562306a36Sopenharmony_ci			!strisglob(pev->point.function))
284662306a36Sopenharmony_ci			event = pev->point.function;
284762306a36Sopenharmony_ci		else
284862306a36Sopenharmony_ci			event = tev->point.realname;
284962306a36Sopenharmony_ci	}
285062306a36Sopenharmony_ci	if (pev->group && !pev->sdt)
285162306a36Sopenharmony_ci		group = pev->group;
285262306a36Sopenharmony_ci	else if (tev->group)
285362306a36Sopenharmony_ci		group = tev->group;
285462306a36Sopenharmony_ci	else
285562306a36Sopenharmony_ci		group = PERFPROBE_GROUP;
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_ci	/* Get an unused new event name */
285862306a36Sopenharmony_ci	ret = get_new_event_name(buf, 64, event, namelist,
285962306a36Sopenharmony_ci				 tev->point.retprobe, allow_suffix);
286062306a36Sopenharmony_ci	if (ret < 0)
286162306a36Sopenharmony_ci		return ret;
286262306a36Sopenharmony_ci
286362306a36Sopenharmony_ci	event = buf;
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	tev->event = strdup(event);
286662306a36Sopenharmony_ci	tev->group = strdup(group);
286762306a36Sopenharmony_ci	if (tev->event == NULL || tev->group == NULL)
286862306a36Sopenharmony_ci		return -ENOMEM;
286962306a36Sopenharmony_ci
287062306a36Sopenharmony_ci	/*
287162306a36Sopenharmony_ci	 * Add new event name to namelist if multiprobe event is NOT
287262306a36Sopenharmony_ci	 * supported, since we have to use new event name for following
287362306a36Sopenharmony_ci	 * probes in that case.
287462306a36Sopenharmony_ci	 */
287562306a36Sopenharmony_ci	if (!multiprobe_event_is_supported())
287662306a36Sopenharmony_ci		strlist__add(namelist, event);
287762306a36Sopenharmony_ci	return 0;
287862306a36Sopenharmony_ci}
287962306a36Sopenharmony_ci
288062306a36Sopenharmony_cistatic int __open_probe_file_and_namelist(bool uprobe,
288162306a36Sopenharmony_ci					  struct strlist **namelist)
288262306a36Sopenharmony_ci{
288362306a36Sopenharmony_ci	int fd;
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci	fd = probe_file__open(PF_FL_RW | (uprobe ? PF_FL_UPROBE : 0));
288662306a36Sopenharmony_ci	if (fd < 0)
288762306a36Sopenharmony_ci		return fd;
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci	/* Get current event names */
289062306a36Sopenharmony_ci	*namelist = probe_file__get_namelist(fd);
289162306a36Sopenharmony_ci	if (!(*namelist)) {
289262306a36Sopenharmony_ci		pr_debug("Failed to get current event list.\n");
289362306a36Sopenharmony_ci		close(fd);
289462306a36Sopenharmony_ci		return -ENOMEM;
289562306a36Sopenharmony_ci	}
289662306a36Sopenharmony_ci	return fd;
289762306a36Sopenharmony_ci}
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_cistatic int __add_probe_trace_events(struct perf_probe_event *pev,
290062306a36Sopenharmony_ci				     struct probe_trace_event *tevs,
290162306a36Sopenharmony_ci				     int ntevs, bool allow_suffix)
290262306a36Sopenharmony_ci{
290362306a36Sopenharmony_ci	int i, fd[2] = {-1, -1}, up, ret;
290462306a36Sopenharmony_ci	struct probe_trace_event *tev = NULL;
290562306a36Sopenharmony_ci	struct probe_cache *cache = NULL;
290662306a36Sopenharmony_ci	struct strlist *namelist[2] = {NULL, NULL};
290762306a36Sopenharmony_ci	struct nscookie nsc;
290862306a36Sopenharmony_ci
290962306a36Sopenharmony_ci	up = pev->uprobes ? 1 : 0;
291062306a36Sopenharmony_ci	fd[up] = __open_probe_file_and_namelist(up, &namelist[up]);
291162306a36Sopenharmony_ci	if (fd[up] < 0)
291262306a36Sopenharmony_ci		return fd[up];
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci	ret = 0;
291562306a36Sopenharmony_ci	for (i = 0; i < ntevs; i++) {
291662306a36Sopenharmony_ci		tev = &tevs[i];
291762306a36Sopenharmony_ci		up = tev->uprobes ? 1 : 0;
291862306a36Sopenharmony_ci		if (fd[up] == -1) {	/* Open the kprobe/uprobe_events */
291962306a36Sopenharmony_ci			fd[up] = __open_probe_file_and_namelist(up,
292062306a36Sopenharmony_ci								&namelist[up]);
292162306a36Sopenharmony_ci			if (fd[up] < 0)
292262306a36Sopenharmony_ci				goto close_out;
292362306a36Sopenharmony_ci		}
292462306a36Sopenharmony_ci		/* Skip if the symbol is out of .text or blacklisted */
292562306a36Sopenharmony_ci		if (!tev->point.symbol && !pev->uprobes)
292662306a36Sopenharmony_ci			continue;
292762306a36Sopenharmony_ci
292862306a36Sopenharmony_ci		/* Set new name for tev (and update namelist) */
292962306a36Sopenharmony_ci		ret = probe_trace_event__set_name(tev, pev, namelist[up],
293062306a36Sopenharmony_ci						  allow_suffix);
293162306a36Sopenharmony_ci		if (ret < 0)
293262306a36Sopenharmony_ci			break;
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci		nsinfo__mountns_enter(pev->nsi, &nsc);
293562306a36Sopenharmony_ci		ret = probe_file__add_event(fd[up], tev);
293662306a36Sopenharmony_ci		nsinfo__mountns_exit(&nsc);
293762306a36Sopenharmony_ci		if (ret < 0)
293862306a36Sopenharmony_ci			break;
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_ci		/*
294162306a36Sopenharmony_ci		 * Probes after the first probe which comes from same
294262306a36Sopenharmony_ci		 * user input are always allowed to add suffix, because
294362306a36Sopenharmony_ci		 * there might be several addresses corresponding to
294462306a36Sopenharmony_ci		 * one code line.
294562306a36Sopenharmony_ci		 */
294662306a36Sopenharmony_ci		allow_suffix = true;
294762306a36Sopenharmony_ci	}
294862306a36Sopenharmony_ci	if (ret == -EINVAL && pev->uprobes)
294962306a36Sopenharmony_ci		warn_uprobe_event_compat(tev);
295062306a36Sopenharmony_ci	if (ret == 0 && probe_conf.cache) {
295162306a36Sopenharmony_ci		cache = probe_cache__new(pev->target, pev->nsi);
295262306a36Sopenharmony_ci		if (!cache ||
295362306a36Sopenharmony_ci		    probe_cache__add_entry(cache, pev, tevs, ntevs) < 0 ||
295462306a36Sopenharmony_ci		    probe_cache__commit(cache) < 0)
295562306a36Sopenharmony_ci			pr_warning("Failed to add event to probe cache\n");
295662306a36Sopenharmony_ci		probe_cache__delete(cache);
295762306a36Sopenharmony_ci	}
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_ciclose_out:
296062306a36Sopenharmony_ci	for (up = 0; up < 2; up++) {
296162306a36Sopenharmony_ci		strlist__delete(namelist[up]);
296262306a36Sopenharmony_ci		if (fd[up] >= 0)
296362306a36Sopenharmony_ci			close(fd[up]);
296462306a36Sopenharmony_ci	}
296562306a36Sopenharmony_ci	return ret;
296662306a36Sopenharmony_ci}
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_cistatic int find_probe_functions(struct map *map, char *name,
296962306a36Sopenharmony_ci				struct symbol **syms)
297062306a36Sopenharmony_ci{
297162306a36Sopenharmony_ci	int found = 0;
297262306a36Sopenharmony_ci	struct symbol *sym;
297362306a36Sopenharmony_ci	struct rb_node *tmp;
297462306a36Sopenharmony_ci	const char *norm, *ver;
297562306a36Sopenharmony_ci	char *buf = NULL;
297662306a36Sopenharmony_ci	bool cut_version = true;
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ci	if (map__load(map) < 0)
297962306a36Sopenharmony_ci		return -EACCES;	/* Possible permission error to load symbols */
298062306a36Sopenharmony_ci
298162306a36Sopenharmony_ci	/* If user gives a version, don't cut off the version from symbols */
298262306a36Sopenharmony_ci	if (strchr(name, '@'))
298362306a36Sopenharmony_ci		cut_version = false;
298462306a36Sopenharmony_ci
298562306a36Sopenharmony_ci	map__for_each_symbol(map, sym, tmp) {
298662306a36Sopenharmony_ci		norm = arch__normalize_symbol_name(sym->name);
298762306a36Sopenharmony_ci		if (!norm)
298862306a36Sopenharmony_ci			continue;
298962306a36Sopenharmony_ci
299062306a36Sopenharmony_ci		if (cut_version) {
299162306a36Sopenharmony_ci			/* We don't care about default symbol or not */
299262306a36Sopenharmony_ci			ver = strchr(norm, '@');
299362306a36Sopenharmony_ci			if (ver) {
299462306a36Sopenharmony_ci				buf = strndup(norm, ver - norm);
299562306a36Sopenharmony_ci				if (!buf)
299662306a36Sopenharmony_ci					return -ENOMEM;
299762306a36Sopenharmony_ci				norm = buf;
299862306a36Sopenharmony_ci			}
299962306a36Sopenharmony_ci		}
300062306a36Sopenharmony_ci
300162306a36Sopenharmony_ci		if (strglobmatch(norm, name)) {
300262306a36Sopenharmony_ci			found++;
300362306a36Sopenharmony_ci			if (syms && found < probe_conf.max_probes)
300462306a36Sopenharmony_ci				syms[found - 1] = sym;
300562306a36Sopenharmony_ci		}
300662306a36Sopenharmony_ci		if (buf)
300762306a36Sopenharmony_ci			zfree(&buf);
300862306a36Sopenharmony_ci	}
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_ci	return found;
301162306a36Sopenharmony_ci}
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_civoid __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused,
301462306a36Sopenharmony_ci				struct probe_trace_event *tev __maybe_unused,
301562306a36Sopenharmony_ci				struct map *map __maybe_unused,
301662306a36Sopenharmony_ci				struct symbol *sym __maybe_unused) { }
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_ci
301962306a36Sopenharmony_cistatic void pr_kallsyms_access_error(void)
302062306a36Sopenharmony_ci{
302162306a36Sopenharmony_ci	pr_err("Please ensure you can read the /proc/kallsyms symbol addresses.\n"
302262306a36Sopenharmony_ci	       "If /proc/sys/kernel/kptr_restrict is '2', you can not read\n"
302362306a36Sopenharmony_ci	       "kernel symbol addresses even if you are a superuser. Please change\n"
302462306a36Sopenharmony_ci	       "it to '1'. If kptr_restrict is '1', the superuser can read the\n"
302562306a36Sopenharmony_ci	       "symbol addresses.\n"
302662306a36Sopenharmony_ci	       "In that case, please run this command again with sudo.\n");
302762306a36Sopenharmony_ci}
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_ci/*
303062306a36Sopenharmony_ci * Find probe function addresses from map.
303162306a36Sopenharmony_ci * Return an error or the number of found probe_trace_event
303262306a36Sopenharmony_ci */
303362306a36Sopenharmony_cistatic int find_probe_trace_events_from_map(struct perf_probe_event *pev,
303462306a36Sopenharmony_ci					    struct probe_trace_event **tevs)
303562306a36Sopenharmony_ci{
303662306a36Sopenharmony_ci	struct map *map = NULL;
303762306a36Sopenharmony_ci	struct ref_reloc_sym *reloc_sym = NULL;
303862306a36Sopenharmony_ci	struct symbol *sym;
303962306a36Sopenharmony_ci	struct symbol **syms = NULL;
304062306a36Sopenharmony_ci	struct probe_trace_event *tev;
304162306a36Sopenharmony_ci	struct perf_probe_point *pp = &pev->point;
304262306a36Sopenharmony_ci	struct probe_trace_point *tp;
304362306a36Sopenharmony_ci	int num_matched_functions;
304462306a36Sopenharmony_ci	int ret, i, j, skipped = 0;
304562306a36Sopenharmony_ci	char *mod_name;
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci	map = get_target_map(pev->target, pev->nsi, pev->uprobes);
304862306a36Sopenharmony_ci	if (!map) {
304962306a36Sopenharmony_ci		ret = -EINVAL;
305062306a36Sopenharmony_ci		goto out;
305162306a36Sopenharmony_ci	}
305262306a36Sopenharmony_ci
305362306a36Sopenharmony_ci	syms = malloc(sizeof(struct symbol *) * probe_conf.max_probes);
305462306a36Sopenharmony_ci	if (!syms) {
305562306a36Sopenharmony_ci		ret = -ENOMEM;
305662306a36Sopenharmony_ci		goto out;
305762306a36Sopenharmony_ci	}
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_ci	/*
306062306a36Sopenharmony_ci	 * Load matched symbols: Since the different local symbols may have
306162306a36Sopenharmony_ci	 * same name but different addresses, this lists all the symbols.
306262306a36Sopenharmony_ci	 */
306362306a36Sopenharmony_ci	num_matched_functions = find_probe_functions(map, pp->function, syms);
306462306a36Sopenharmony_ci	if (num_matched_functions <= 0) {
306562306a36Sopenharmony_ci		if (num_matched_functions == -EACCES) {
306662306a36Sopenharmony_ci			pr_err("Failed to load symbols from %s\n",
306762306a36Sopenharmony_ci			       pev->target ?: "/proc/kallsyms");
306862306a36Sopenharmony_ci			if (pev->target)
306962306a36Sopenharmony_ci				pr_err("Please ensure the file is not stripped.\n");
307062306a36Sopenharmony_ci			else
307162306a36Sopenharmony_ci				pr_kallsyms_access_error();
307262306a36Sopenharmony_ci		} else
307362306a36Sopenharmony_ci			pr_err("Failed to find symbol %s in %s\n", pp->function,
307462306a36Sopenharmony_ci				pev->target ? : "kernel");
307562306a36Sopenharmony_ci		ret = -ENOENT;
307662306a36Sopenharmony_ci		goto out;
307762306a36Sopenharmony_ci	} else if (num_matched_functions > probe_conf.max_probes) {
307862306a36Sopenharmony_ci		pr_err("Too many functions matched in %s\n",
307962306a36Sopenharmony_ci			pev->target ? : "kernel");
308062306a36Sopenharmony_ci		ret = -E2BIG;
308162306a36Sopenharmony_ci		goto out;
308262306a36Sopenharmony_ci	}
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_ci	/* Note that the symbols in the kmodule are not relocated */
308562306a36Sopenharmony_ci	if (!pev->uprobes && !pev->target &&
308662306a36Sopenharmony_ci			(!pp->retprobe || kretprobe_offset_is_supported())) {
308762306a36Sopenharmony_ci		reloc_sym = kernel_get_ref_reloc_sym(NULL);
308862306a36Sopenharmony_ci		if (!reloc_sym) {
308962306a36Sopenharmony_ci			pr_warning("Relocated base symbol is not found! "
309062306a36Sopenharmony_ci				   "Check /proc/sys/kernel/kptr_restrict\n"
309162306a36Sopenharmony_ci				   "and /proc/sys/kernel/perf_event_paranoid. "
309262306a36Sopenharmony_ci				   "Or run as privileged perf user.\n\n");
309362306a36Sopenharmony_ci			ret = -EINVAL;
309462306a36Sopenharmony_ci			goto out;
309562306a36Sopenharmony_ci		}
309662306a36Sopenharmony_ci	}
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci	/* Setup result trace-probe-events */
309962306a36Sopenharmony_ci	*tevs = zalloc(sizeof(*tev) * num_matched_functions);
310062306a36Sopenharmony_ci	if (!*tevs) {
310162306a36Sopenharmony_ci		ret = -ENOMEM;
310262306a36Sopenharmony_ci		goto out;
310362306a36Sopenharmony_ci	}
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_ci	ret = 0;
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci	for (j = 0; j < num_matched_functions; j++) {
310862306a36Sopenharmony_ci		sym = syms[j];
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ci		if (sym->type != STT_FUNC)
311162306a36Sopenharmony_ci			continue;
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci		/* There can be duplicated symbols in the map */
311462306a36Sopenharmony_ci		for (i = 0; i < j; i++)
311562306a36Sopenharmony_ci			if (sym->start == syms[i]->start) {
311662306a36Sopenharmony_ci				pr_debug("Found duplicated symbol %s @ %" PRIx64 "\n",
311762306a36Sopenharmony_ci					 sym->name, sym->start);
311862306a36Sopenharmony_ci				break;
311962306a36Sopenharmony_ci			}
312062306a36Sopenharmony_ci		if (i != j)
312162306a36Sopenharmony_ci			continue;
312262306a36Sopenharmony_ci
312362306a36Sopenharmony_ci		tev = (*tevs) + ret;
312462306a36Sopenharmony_ci		tp = &tev->point;
312562306a36Sopenharmony_ci		if (ret == num_matched_functions) {
312662306a36Sopenharmony_ci			pr_warning("Too many symbols are listed. Skip it.\n");
312762306a36Sopenharmony_ci			break;
312862306a36Sopenharmony_ci		}
312962306a36Sopenharmony_ci		ret++;
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci		if (pp->offset > sym->end - sym->start) {
313262306a36Sopenharmony_ci			pr_warning("Offset %ld is bigger than the size of %s\n",
313362306a36Sopenharmony_ci				   pp->offset, sym->name);
313462306a36Sopenharmony_ci			ret = -ENOENT;
313562306a36Sopenharmony_ci			goto err_out;
313662306a36Sopenharmony_ci		}
313762306a36Sopenharmony_ci		/* Add one probe point */
313862306a36Sopenharmony_ci		tp->address = map__unmap_ip(map, sym->start) + pp->offset;
313962306a36Sopenharmony_ci
314062306a36Sopenharmony_ci		/* Check the kprobe (not in module) is within .text  */
314162306a36Sopenharmony_ci		if (!pev->uprobes && !pev->target &&
314262306a36Sopenharmony_ci		    kprobe_warn_out_range(sym->name, tp->address)) {
314362306a36Sopenharmony_ci			tp->symbol = NULL;	/* Skip it */
314462306a36Sopenharmony_ci			skipped++;
314562306a36Sopenharmony_ci		} else if (reloc_sym) {
314662306a36Sopenharmony_ci			tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out);
314762306a36Sopenharmony_ci			tp->offset = tp->address - reloc_sym->addr;
314862306a36Sopenharmony_ci		} else {
314962306a36Sopenharmony_ci			tp->symbol = strdup_or_goto(sym->name, nomem_out);
315062306a36Sopenharmony_ci			tp->offset = pp->offset;
315162306a36Sopenharmony_ci		}
315262306a36Sopenharmony_ci		tp->realname = strdup_or_goto(sym->name, nomem_out);
315362306a36Sopenharmony_ci
315462306a36Sopenharmony_ci		tp->retprobe = pp->retprobe;
315562306a36Sopenharmony_ci		if (pev->target) {
315662306a36Sopenharmony_ci			if (pev->uprobes) {
315762306a36Sopenharmony_ci				tev->point.module = strdup_or_goto(pev->target,
315862306a36Sopenharmony_ci								   nomem_out);
315962306a36Sopenharmony_ci			} else {
316062306a36Sopenharmony_ci				mod_name = find_module_name(pev->target);
316162306a36Sopenharmony_ci				tev->point.module =
316262306a36Sopenharmony_ci					strdup(mod_name ? mod_name : pev->target);
316362306a36Sopenharmony_ci				free(mod_name);
316462306a36Sopenharmony_ci				if (!tev->point.module)
316562306a36Sopenharmony_ci					goto nomem_out;
316662306a36Sopenharmony_ci			}
316762306a36Sopenharmony_ci		}
316862306a36Sopenharmony_ci		tev->uprobes = pev->uprobes;
316962306a36Sopenharmony_ci		tev->nargs = pev->nargs;
317062306a36Sopenharmony_ci		if (tev->nargs) {
317162306a36Sopenharmony_ci			tev->args = zalloc(sizeof(struct probe_trace_arg) *
317262306a36Sopenharmony_ci					   tev->nargs);
317362306a36Sopenharmony_ci			if (tev->args == NULL)
317462306a36Sopenharmony_ci				goto nomem_out;
317562306a36Sopenharmony_ci		}
317662306a36Sopenharmony_ci		for (i = 0; i < tev->nargs; i++) {
317762306a36Sopenharmony_ci			if (pev->args[i].name)
317862306a36Sopenharmony_ci				tev->args[i].name =
317962306a36Sopenharmony_ci					strdup_or_goto(pev->args[i].name,
318062306a36Sopenharmony_ci							nomem_out);
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_ci			tev->args[i].value = strdup_or_goto(pev->args[i].var,
318362306a36Sopenharmony_ci							    nomem_out);
318462306a36Sopenharmony_ci			if (pev->args[i].type)
318562306a36Sopenharmony_ci				tev->args[i].type =
318662306a36Sopenharmony_ci					strdup_or_goto(pev->args[i].type,
318762306a36Sopenharmony_ci							nomem_out);
318862306a36Sopenharmony_ci		}
318962306a36Sopenharmony_ci		arch__fix_tev_from_maps(pev, tev, map, sym);
319062306a36Sopenharmony_ci	}
319162306a36Sopenharmony_ci	if (ret == skipped) {
319262306a36Sopenharmony_ci		ret = -ENOENT;
319362306a36Sopenharmony_ci		goto err_out;
319462306a36Sopenharmony_ci	}
319562306a36Sopenharmony_ci
319662306a36Sopenharmony_ciout:
319762306a36Sopenharmony_ci	map__put(map);
319862306a36Sopenharmony_ci	free(syms);
319962306a36Sopenharmony_ci	return ret;
320062306a36Sopenharmony_ci
320162306a36Sopenharmony_cinomem_out:
320262306a36Sopenharmony_ci	ret = -ENOMEM;
320362306a36Sopenharmony_cierr_out:
320462306a36Sopenharmony_ci	clear_probe_trace_events(*tevs, num_matched_functions);
320562306a36Sopenharmony_ci	zfree(tevs);
320662306a36Sopenharmony_ci	goto out;
320762306a36Sopenharmony_ci}
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_cistatic int try_to_find_absolute_address(struct perf_probe_event *pev,
321062306a36Sopenharmony_ci					struct probe_trace_event **tevs)
321162306a36Sopenharmony_ci{
321262306a36Sopenharmony_ci	struct perf_probe_point *pp = &pev->point;
321362306a36Sopenharmony_ci	struct probe_trace_event *tev;
321462306a36Sopenharmony_ci	struct probe_trace_point *tp;
321562306a36Sopenharmony_ci	int i, err;
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci	if (!(pev->point.function && !strncmp(pev->point.function, "0x", 2)))
321862306a36Sopenharmony_ci		return -EINVAL;
321962306a36Sopenharmony_ci	if (perf_probe_event_need_dwarf(pev))
322062306a36Sopenharmony_ci		return -EINVAL;
322162306a36Sopenharmony_ci
322262306a36Sopenharmony_ci	/*
322362306a36Sopenharmony_ci	 * This is 'perf probe /lib/libc.so 0xabcd'. Try to probe at
322462306a36Sopenharmony_ci	 * absolute address.
322562306a36Sopenharmony_ci	 *
322662306a36Sopenharmony_ci	 * Only one tev can be generated by this.
322762306a36Sopenharmony_ci	 */
322862306a36Sopenharmony_ci	*tevs = zalloc(sizeof(*tev));
322962306a36Sopenharmony_ci	if (!*tevs)
323062306a36Sopenharmony_ci		return -ENOMEM;
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_ci	tev = *tevs;
323362306a36Sopenharmony_ci	tp = &tev->point;
323462306a36Sopenharmony_ci
323562306a36Sopenharmony_ci	/*
323662306a36Sopenharmony_ci	 * Don't use tp->offset, use address directly, because
323762306a36Sopenharmony_ci	 * in synthesize_probe_trace_command() address cannot be
323862306a36Sopenharmony_ci	 * zero.
323962306a36Sopenharmony_ci	 */
324062306a36Sopenharmony_ci	tp->address = pev->point.abs_address;
324162306a36Sopenharmony_ci	tp->retprobe = pp->retprobe;
324262306a36Sopenharmony_ci	tev->uprobes = pev->uprobes;
324362306a36Sopenharmony_ci
324462306a36Sopenharmony_ci	err = -ENOMEM;
324562306a36Sopenharmony_ci	/*
324662306a36Sopenharmony_ci	 * Give it a '0x' leading symbol name.
324762306a36Sopenharmony_ci	 * In __add_probe_trace_events, a NULL symbol is interpreted as
324862306a36Sopenharmony_ci	 * invalid.
324962306a36Sopenharmony_ci	 */
325062306a36Sopenharmony_ci	if (asprintf(&tp->symbol, "0x%" PRIx64, tp->address) < 0)
325162306a36Sopenharmony_ci		goto errout;
325262306a36Sopenharmony_ci
325362306a36Sopenharmony_ci	/* For kprobe, check range */
325462306a36Sopenharmony_ci	if ((!tev->uprobes) &&
325562306a36Sopenharmony_ci	    (kprobe_warn_out_range(tev->point.symbol,
325662306a36Sopenharmony_ci				   tev->point.address))) {
325762306a36Sopenharmony_ci		err = -EACCES;
325862306a36Sopenharmony_ci		goto errout;
325962306a36Sopenharmony_ci	}
326062306a36Sopenharmony_ci
326162306a36Sopenharmony_ci	if (asprintf(&tp->realname, "abs_%" PRIx64, tp->address) < 0)
326262306a36Sopenharmony_ci		goto errout;
326362306a36Sopenharmony_ci
326462306a36Sopenharmony_ci	if (pev->target) {
326562306a36Sopenharmony_ci		tp->module = strdup(pev->target);
326662306a36Sopenharmony_ci		if (!tp->module)
326762306a36Sopenharmony_ci			goto errout;
326862306a36Sopenharmony_ci	}
326962306a36Sopenharmony_ci
327062306a36Sopenharmony_ci	if (tev->group) {
327162306a36Sopenharmony_ci		tev->group = strdup(pev->group);
327262306a36Sopenharmony_ci		if (!tev->group)
327362306a36Sopenharmony_ci			goto errout;
327462306a36Sopenharmony_ci	}
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci	if (pev->event) {
327762306a36Sopenharmony_ci		tev->event = strdup(pev->event);
327862306a36Sopenharmony_ci		if (!tev->event)
327962306a36Sopenharmony_ci			goto errout;
328062306a36Sopenharmony_ci	}
328162306a36Sopenharmony_ci
328262306a36Sopenharmony_ci	tev->nargs = pev->nargs;
328362306a36Sopenharmony_ci	tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
328462306a36Sopenharmony_ci	if (!tev->args)
328562306a36Sopenharmony_ci		goto errout;
328662306a36Sopenharmony_ci
328762306a36Sopenharmony_ci	for (i = 0; i < tev->nargs; i++)
328862306a36Sopenharmony_ci		copy_to_probe_trace_arg(&tev->args[i], &pev->args[i]);
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci	return 1;
329162306a36Sopenharmony_ci
329262306a36Sopenharmony_cierrout:
329362306a36Sopenharmony_ci	clear_probe_trace_events(*tevs, 1);
329462306a36Sopenharmony_ci	*tevs = NULL;
329562306a36Sopenharmony_ci	return err;
329662306a36Sopenharmony_ci}
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_ci/* Concatenate two arrays */
329962306a36Sopenharmony_cistatic void *memcat(void *a, size_t sz_a, void *b, size_t sz_b)
330062306a36Sopenharmony_ci{
330162306a36Sopenharmony_ci	void *ret;
330262306a36Sopenharmony_ci
330362306a36Sopenharmony_ci	ret = malloc(sz_a + sz_b);
330462306a36Sopenharmony_ci	if (ret) {
330562306a36Sopenharmony_ci		memcpy(ret, a, sz_a);
330662306a36Sopenharmony_ci		memcpy(ret + sz_a, b, sz_b);
330762306a36Sopenharmony_ci	}
330862306a36Sopenharmony_ci	return ret;
330962306a36Sopenharmony_ci}
331062306a36Sopenharmony_ci
331162306a36Sopenharmony_cistatic int
331262306a36Sopenharmony_ciconcat_probe_trace_events(struct probe_trace_event **tevs, int *ntevs,
331362306a36Sopenharmony_ci			  struct probe_trace_event **tevs2, int ntevs2)
331462306a36Sopenharmony_ci{
331562306a36Sopenharmony_ci	struct probe_trace_event *new_tevs;
331662306a36Sopenharmony_ci	int ret = 0;
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci	if (*ntevs == 0) {
331962306a36Sopenharmony_ci		*tevs = *tevs2;
332062306a36Sopenharmony_ci		*ntevs = ntevs2;
332162306a36Sopenharmony_ci		*tevs2 = NULL;
332262306a36Sopenharmony_ci		return 0;
332362306a36Sopenharmony_ci	}
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_ci	if (*ntevs + ntevs2 > probe_conf.max_probes)
332662306a36Sopenharmony_ci		ret = -E2BIG;
332762306a36Sopenharmony_ci	else {
332862306a36Sopenharmony_ci		/* Concatenate the array of probe_trace_event */
332962306a36Sopenharmony_ci		new_tevs = memcat(*tevs, (*ntevs) * sizeof(**tevs),
333062306a36Sopenharmony_ci				  *tevs2, ntevs2 * sizeof(**tevs2));
333162306a36Sopenharmony_ci		if (!new_tevs)
333262306a36Sopenharmony_ci			ret = -ENOMEM;
333362306a36Sopenharmony_ci		else {
333462306a36Sopenharmony_ci			free(*tevs);
333562306a36Sopenharmony_ci			*tevs = new_tevs;
333662306a36Sopenharmony_ci			*ntevs += ntevs2;
333762306a36Sopenharmony_ci		}
333862306a36Sopenharmony_ci	}
333962306a36Sopenharmony_ci	if (ret < 0)
334062306a36Sopenharmony_ci		clear_probe_trace_events(*tevs2, ntevs2);
334162306a36Sopenharmony_ci	zfree(tevs2);
334262306a36Sopenharmony_ci
334362306a36Sopenharmony_ci	return ret;
334462306a36Sopenharmony_ci}
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_ci/*
334762306a36Sopenharmony_ci * Try to find probe_trace_event from given probe caches. Return the number
334862306a36Sopenharmony_ci * of cached events found, if an error occurs return the error.
334962306a36Sopenharmony_ci */
335062306a36Sopenharmony_cistatic int find_cached_events(struct perf_probe_event *pev,
335162306a36Sopenharmony_ci			      struct probe_trace_event **tevs,
335262306a36Sopenharmony_ci			      const char *target)
335362306a36Sopenharmony_ci{
335462306a36Sopenharmony_ci	struct probe_cache *cache;
335562306a36Sopenharmony_ci	struct probe_cache_entry *entry;
335662306a36Sopenharmony_ci	struct probe_trace_event *tmp_tevs = NULL;
335762306a36Sopenharmony_ci	int ntevs = 0;
335862306a36Sopenharmony_ci	int ret = 0;
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_ci	cache = probe_cache__new(target, pev->nsi);
336162306a36Sopenharmony_ci	/* Return 0 ("not found") if the target has no probe cache. */
336262306a36Sopenharmony_ci	if (!cache)
336362306a36Sopenharmony_ci		return 0;
336462306a36Sopenharmony_ci
336562306a36Sopenharmony_ci	for_each_probe_cache_entry(entry, cache) {
336662306a36Sopenharmony_ci		/* Skip the cache entry which has no name */
336762306a36Sopenharmony_ci		if (!entry->pev.event || !entry->pev.group)
336862306a36Sopenharmony_ci			continue;
336962306a36Sopenharmony_ci		if ((!pev->group || strglobmatch(entry->pev.group, pev->group)) &&
337062306a36Sopenharmony_ci		    strglobmatch(entry->pev.event, pev->event)) {
337162306a36Sopenharmony_ci			ret = probe_cache_entry__get_event(entry, &tmp_tevs);
337262306a36Sopenharmony_ci			if (ret > 0)
337362306a36Sopenharmony_ci				ret = concat_probe_trace_events(tevs, &ntevs,
337462306a36Sopenharmony_ci								&tmp_tevs, ret);
337562306a36Sopenharmony_ci			if (ret < 0)
337662306a36Sopenharmony_ci				break;
337762306a36Sopenharmony_ci		}
337862306a36Sopenharmony_ci	}
337962306a36Sopenharmony_ci	probe_cache__delete(cache);
338062306a36Sopenharmony_ci	if (ret < 0) {
338162306a36Sopenharmony_ci		clear_probe_trace_events(*tevs, ntevs);
338262306a36Sopenharmony_ci		zfree(tevs);
338362306a36Sopenharmony_ci	} else {
338462306a36Sopenharmony_ci		ret = ntevs;
338562306a36Sopenharmony_ci		if (ntevs > 0 && target && target[0] == '/')
338662306a36Sopenharmony_ci			pev->uprobes = true;
338762306a36Sopenharmony_ci	}
338862306a36Sopenharmony_ci
338962306a36Sopenharmony_ci	return ret;
339062306a36Sopenharmony_ci}
339162306a36Sopenharmony_ci
339262306a36Sopenharmony_ci/* Try to find probe_trace_event from all probe caches */
339362306a36Sopenharmony_cistatic int find_cached_events_all(struct perf_probe_event *pev,
339462306a36Sopenharmony_ci				   struct probe_trace_event **tevs)
339562306a36Sopenharmony_ci{
339662306a36Sopenharmony_ci	struct probe_trace_event *tmp_tevs = NULL;
339762306a36Sopenharmony_ci	struct strlist *bidlist;
339862306a36Sopenharmony_ci	struct str_node *nd;
339962306a36Sopenharmony_ci	char *pathname;
340062306a36Sopenharmony_ci	int ntevs = 0;
340162306a36Sopenharmony_ci	int ret;
340262306a36Sopenharmony_ci
340362306a36Sopenharmony_ci	/* Get the buildid list of all valid caches */
340462306a36Sopenharmony_ci	bidlist = build_id_cache__list_all(true);
340562306a36Sopenharmony_ci	if (!bidlist) {
340662306a36Sopenharmony_ci		ret = -errno;
340762306a36Sopenharmony_ci		pr_debug("Failed to get buildids: %d\n", ret);
340862306a36Sopenharmony_ci		return ret;
340962306a36Sopenharmony_ci	}
341062306a36Sopenharmony_ci
341162306a36Sopenharmony_ci	ret = 0;
341262306a36Sopenharmony_ci	strlist__for_each_entry(nd, bidlist) {
341362306a36Sopenharmony_ci		pathname = build_id_cache__origname(nd->s);
341462306a36Sopenharmony_ci		ret = find_cached_events(pev, &tmp_tevs, pathname);
341562306a36Sopenharmony_ci		/* In the case of cnt == 0, we just skip it */
341662306a36Sopenharmony_ci		if (ret > 0)
341762306a36Sopenharmony_ci			ret = concat_probe_trace_events(tevs, &ntevs,
341862306a36Sopenharmony_ci							&tmp_tevs, ret);
341962306a36Sopenharmony_ci		free(pathname);
342062306a36Sopenharmony_ci		if (ret < 0)
342162306a36Sopenharmony_ci			break;
342262306a36Sopenharmony_ci	}
342362306a36Sopenharmony_ci	strlist__delete(bidlist);
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_ci	if (ret < 0) {
342662306a36Sopenharmony_ci		clear_probe_trace_events(*tevs, ntevs);
342762306a36Sopenharmony_ci		zfree(tevs);
342862306a36Sopenharmony_ci	} else
342962306a36Sopenharmony_ci		ret = ntevs;
343062306a36Sopenharmony_ci
343162306a36Sopenharmony_ci	return ret;
343262306a36Sopenharmony_ci}
343362306a36Sopenharmony_ci
343462306a36Sopenharmony_cistatic int find_probe_trace_events_from_cache(struct perf_probe_event *pev,
343562306a36Sopenharmony_ci					      struct probe_trace_event **tevs)
343662306a36Sopenharmony_ci{
343762306a36Sopenharmony_ci	struct probe_cache *cache;
343862306a36Sopenharmony_ci	struct probe_cache_entry *entry;
343962306a36Sopenharmony_ci	struct probe_trace_event *tev;
344062306a36Sopenharmony_ci	struct str_node *node;
344162306a36Sopenharmony_ci	int ret, i;
344262306a36Sopenharmony_ci
344362306a36Sopenharmony_ci	if (pev->sdt) {
344462306a36Sopenharmony_ci		/* For SDT/cached events, we use special search functions */
344562306a36Sopenharmony_ci		if (!pev->target)
344662306a36Sopenharmony_ci			return find_cached_events_all(pev, tevs);
344762306a36Sopenharmony_ci		else
344862306a36Sopenharmony_ci			return find_cached_events(pev, tevs, pev->target);
344962306a36Sopenharmony_ci	}
345062306a36Sopenharmony_ci	cache = probe_cache__new(pev->target, pev->nsi);
345162306a36Sopenharmony_ci	if (!cache)
345262306a36Sopenharmony_ci		return 0;
345362306a36Sopenharmony_ci
345462306a36Sopenharmony_ci	entry = probe_cache__find(cache, pev);
345562306a36Sopenharmony_ci	if (!entry) {
345662306a36Sopenharmony_ci		/* SDT must be in the cache */
345762306a36Sopenharmony_ci		ret = pev->sdt ? -ENOENT : 0;
345862306a36Sopenharmony_ci		goto out;
345962306a36Sopenharmony_ci	}
346062306a36Sopenharmony_ci
346162306a36Sopenharmony_ci	ret = strlist__nr_entries(entry->tevlist);
346262306a36Sopenharmony_ci	if (ret > probe_conf.max_probes) {
346362306a36Sopenharmony_ci		pr_debug("Too many entries matched in the cache of %s\n",
346462306a36Sopenharmony_ci			 pev->target ? : "kernel");
346562306a36Sopenharmony_ci		ret = -E2BIG;
346662306a36Sopenharmony_ci		goto out;
346762306a36Sopenharmony_ci	}
346862306a36Sopenharmony_ci
346962306a36Sopenharmony_ci	*tevs = zalloc(ret * sizeof(*tev));
347062306a36Sopenharmony_ci	if (!*tevs) {
347162306a36Sopenharmony_ci		ret = -ENOMEM;
347262306a36Sopenharmony_ci		goto out;
347362306a36Sopenharmony_ci	}
347462306a36Sopenharmony_ci
347562306a36Sopenharmony_ci	i = 0;
347662306a36Sopenharmony_ci	strlist__for_each_entry(node, entry->tevlist) {
347762306a36Sopenharmony_ci		tev = &(*tevs)[i++];
347862306a36Sopenharmony_ci		ret = parse_probe_trace_command(node->s, tev);
347962306a36Sopenharmony_ci		if (ret < 0)
348062306a36Sopenharmony_ci			goto out;
348162306a36Sopenharmony_ci		/* Set the uprobes attribute as same as original */
348262306a36Sopenharmony_ci		tev->uprobes = pev->uprobes;
348362306a36Sopenharmony_ci	}
348462306a36Sopenharmony_ci	ret = i;
348562306a36Sopenharmony_ci
348662306a36Sopenharmony_ciout:
348762306a36Sopenharmony_ci	probe_cache__delete(cache);
348862306a36Sopenharmony_ci	return ret;
348962306a36Sopenharmony_ci}
349062306a36Sopenharmony_ci
349162306a36Sopenharmony_cistatic int convert_to_probe_trace_events(struct perf_probe_event *pev,
349262306a36Sopenharmony_ci					 struct probe_trace_event **tevs)
349362306a36Sopenharmony_ci{
349462306a36Sopenharmony_ci	int ret;
349562306a36Sopenharmony_ci
349662306a36Sopenharmony_ci	if (!pev->group && !pev->sdt) {
349762306a36Sopenharmony_ci		/* Set group name if not given */
349862306a36Sopenharmony_ci		if (!pev->uprobes) {
349962306a36Sopenharmony_ci			pev->group = strdup(PERFPROBE_GROUP);
350062306a36Sopenharmony_ci			ret = pev->group ? 0 : -ENOMEM;
350162306a36Sopenharmony_ci		} else
350262306a36Sopenharmony_ci			ret = convert_exec_to_group(pev->target, &pev->group);
350362306a36Sopenharmony_ci		if (ret != 0) {
350462306a36Sopenharmony_ci			pr_warning("Failed to make a group name.\n");
350562306a36Sopenharmony_ci			return ret;
350662306a36Sopenharmony_ci		}
350762306a36Sopenharmony_ci	}
350862306a36Sopenharmony_ci
350962306a36Sopenharmony_ci	ret = try_to_find_absolute_address(pev, tevs);
351062306a36Sopenharmony_ci	if (ret > 0)
351162306a36Sopenharmony_ci		return ret;
351262306a36Sopenharmony_ci
351362306a36Sopenharmony_ci	/* At first, we need to lookup cache entry */
351462306a36Sopenharmony_ci	ret = find_probe_trace_events_from_cache(pev, tevs);
351562306a36Sopenharmony_ci	if (ret > 0 || pev->sdt)	/* SDT can be found only in the cache */
351662306a36Sopenharmony_ci		return ret == 0 ? -ENOENT : ret; /* Found in probe cache */
351762306a36Sopenharmony_ci
351862306a36Sopenharmony_ci	/* Convert perf_probe_event with debuginfo */
351962306a36Sopenharmony_ci	ret = try_to_find_probe_trace_events(pev, tevs);
352062306a36Sopenharmony_ci	if (ret != 0)
352162306a36Sopenharmony_ci		return ret;	/* Found in debuginfo or got an error */
352262306a36Sopenharmony_ci
352362306a36Sopenharmony_ci	return find_probe_trace_events_from_map(pev, tevs);
352462306a36Sopenharmony_ci}
352562306a36Sopenharmony_ci
352662306a36Sopenharmony_ciint convert_perf_probe_events(struct perf_probe_event *pevs, int npevs)
352762306a36Sopenharmony_ci{
352862306a36Sopenharmony_ci	int i, ret;
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_ci	/* Loop 1: convert all events */
353162306a36Sopenharmony_ci	for (i = 0; i < npevs; i++) {
353262306a36Sopenharmony_ci		/* Init kprobe blacklist if needed */
353362306a36Sopenharmony_ci		if (!pevs[i].uprobes)
353462306a36Sopenharmony_ci			kprobe_blacklist__init();
353562306a36Sopenharmony_ci		/* Convert with or without debuginfo */
353662306a36Sopenharmony_ci		ret  = convert_to_probe_trace_events(&pevs[i], &pevs[i].tevs);
353762306a36Sopenharmony_ci		if (ret < 0)
353862306a36Sopenharmony_ci			return ret;
353962306a36Sopenharmony_ci		pevs[i].ntevs = ret;
354062306a36Sopenharmony_ci	}
354162306a36Sopenharmony_ci	/* This just release blacklist only if allocated */
354262306a36Sopenharmony_ci	kprobe_blacklist__release();
354362306a36Sopenharmony_ci
354462306a36Sopenharmony_ci	return 0;
354562306a36Sopenharmony_ci}
354662306a36Sopenharmony_ci
354762306a36Sopenharmony_cistatic int show_probe_trace_event(struct probe_trace_event *tev)
354862306a36Sopenharmony_ci{
354962306a36Sopenharmony_ci	char *buf = synthesize_probe_trace_command(tev);
355062306a36Sopenharmony_ci
355162306a36Sopenharmony_ci	if (!buf) {
355262306a36Sopenharmony_ci		pr_debug("Failed to synthesize probe trace event.\n");
355362306a36Sopenharmony_ci		return -EINVAL;
355462306a36Sopenharmony_ci	}
355562306a36Sopenharmony_ci
355662306a36Sopenharmony_ci	/* Showing definition always go stdout */
355762306a36Sopenharmony_ci	printf("%s\n", buf);
355862306a36Sopenharmony_ci	free(buf);
355962306a36Sopenharmony_ci
356062306a36Sopenharmony_ci	return 0;
356162306a36Sopenharmony_ci}
356262306a36Sopenharmony_ci
356362306a36Sopenharmony_ciint show_probe_trace_events(struct perf_probe_event *pevs, int npevs)
356462306a36Sopenharmony_ci{
356562306a36Sopenharmony_ci	struct strlist *namelist = strlist__new(NULL, NULL);
356662306a36Sopenharmony_ci	struct probe_trace_event *tev;
356762306a36Sopenharmony_ci	struct perf_probe_event *pev;
356862306a36Sopenharmony_ci	int i, j, ret = 0;
356962306a36Sopenharmony_ci
357062306a36Sopenharmony_ci	if (!namelist)
357162306a36Sopenharmony_ci		return -ENOMEM;
357262306a36Sopenharmony_ci
357362306a36Sopenharmony_ci	for (j = 0; j < npevs && !ret; j++) {
357462306a36Sopenharmony_ci		pev = &pevs[j];
357562306a36Sopenharmony_ci		for (i = 0; i < pev->ntevs && !ret; i++) {
357662306a36Sopenharmony_ci			tev = &pev->tevs[i];
357762306a36Sopenharmony_ci			/* Skip if the symbol is out of .text or blacklisted */
357862306a36Sopenharmony_ci			if (!tev->point.symbol && !pev->uprobes)
357962306a36Sopenharmony_ci				continue;
358062306a36Sopenharmony_ci
358162306a36Sopenharmony_ci			/* Set new name for tev (and update namelist) */
358262306a36Sopenharmony_ci			ret = probe_trace_event__set_name(tev, pev,
358362306a36Sopenharmony_ci							  namelist, true);
358462306a36Sopenharmony_ci			if (!ret)
358562306a36Sopenharmony_ci				ret = show_probe_trace_event(tev);
358662306a36Sopenharmony_ci		}
358762306a36Sopenharmony_ci	}
358862306a36Sopenharmony_ci	strlist__delete(namelist);
358962306a36Sopenharmony_ci
359062306a36Sopenharmony_ci	return ret;
359162306a36Sopenharmony_ci}
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_cistatic int show_bootconfig_event(struct probe_trace_event *tev)
359462306a36Sopenharmony_ci{
359562306a36Sopenharmony_ci	struct probe_trace_point *tp = &tev->point;
359662306a36Sopenharmony_ci	struct strbuf buf;
359762306a36Sopenharmony_ci	char *ret = NULL;
359862306a36Sopenharmony_ci	int err;
359962306a36Sopenharmony_ci
360062306a36Sopenharmony_ci	if (strbuf_init(&buf, 32) < 0)
360162306a36Sopenharmony_ci		return -ENOMEM;
360262306a36Sopenharmony_ci
360362306a36Sopenharmony_ci	err = synthesize_kprobe_trace_def(tp, &buf);
360462306a36Sopenharmony_ci	if (err >= 0)
360562306a36Sopenharmony_ci		err = synthesize_probe_trace_args(tev, &buf);
360662306a36Sopenharmony_ci	if (err >= 0)
360762306a36Sopenharmony_ci		ret = strbuf_detach(&buf, NULL);
360862306a36Sopenharmony_ci	strbuf_release(&buf);
360962306a36Sopenharmony_ci
361062306a36Sopenharmony_ci	if (ret) {
361162306a36Sopenharmony_ci		printf("'%s'", ret);
361262306a36Sopenharmony_ci		free(ret);
361362306a36Sopenharmony_ci	}
361462306a36Sopenharmony_ci
361562306a36Sopenharmony_ci	return err;
361662306a36Sopenharmony_ci}
361762306a36Sopenharmony_ci
361862306a36Sopenharmony_ciint show_bootconfig_events(struct perf_probe_event *pevs, int npevs)
361962306a36Sopenharmony_ci{
362062306a36Sopenharmony_ci	struct strlist *namelist = strlist__new(NULL, NULL);
362162306a36Sopenharmony_ci	struct probe_trace_event *tev;
362262306a36Sopenharmony_ci	struct perf_probe_event *pev;
362362306a36Sopenharmony_ci	char *cur_name = NULL;
362462306a36Sopenharmony_ci	int i, j, ret = 0;
362562306a36Sopenharmony_ci
362662306a36Sopenharmony_ci	if (!namelist)
362762306a36Sopenharmony_ci		return -ENOMEM;
362862306a36Sopenharmony_ci
362962306a36Sopenharmony_ci	for (j = 0; j < npevs && !ret; j++) {
363062306a36Sopenharmony_ci		pev = &pevs[j];
363162306a36Sopenharmony_ci		if (pev->group && strcmp(pev->group, "probe"))
363262306a36Sopenharmony_ci			pr_warning("WARN: Group name %s is ignored\n", pev->group);
363362306a36Sopenharmony_ci		if (pev->uprobes) {
363462306a36Sopenharmony_ci			pr_warning("ERROR: Bootconfig doesn't support uprobes\n");
363562306a36Sopenharmony_ci			ret = -EINVAL;
363662306a36Sopenharmony_ci			break;
363762306a36Sopenharmony_ci		}
363862306a36Sopenharmony_ci		for (i = 0; i < pev->ntevs && !ret; i++) {
363962306a36Sopenharmony_ci			tev = &pev->tevs[i];
364062306a36Sopenharmony_ci			/* Skip if the symbol is out of .text or blacklisted */
364162306a36Sopenharmony_ci			if (!tev->point.symbol && !pev->uprobes)
364262306a36Sopenharmony_ci				continue;
364362306a36Sopenharmony_ci
364462306a36Sopenharmony_ci			/* Set new name for tev (and update namelist) */
364562306a36Sopenharmony_ci			ret = probe_trace_event__set_name(tev, pev,
364662306a36Sopenharmony_ci							  namelist, true);
364762306a36Sopenharmony_ci			if (ret)
364862306a36Sopenharmony_ci				break;
364962306a36Sopenharmony_ci
365062306a36Sopenharmony_ci			if (!cur_name || strcmp(cur_name, tev->event)) {
365162306a36Sopenharmony_ci				printf("%sftrace.event.kprobes.%s.probe = ",
365262306a36Sopenharmony_ci					cur_name ? "\n" : "", tev->event);
365362306a36Sopenharmony_ci				cur_name = tev->event;
365462306a36Sopenharmony_ci			} else
365562306a36Sopenharmony_ci				printf(", ");
365662306a36Sopenharmony_ci			ret = show_bootconfig_event(tev);
365762306a36Sopenharmony_ci		}
365862306a36Sopenharmony_ci	}
365962306a36Sopenharmony_ci	printf("\n");
366062306a36Sopenharmony_ci	strlist__delete(namelist);
366162306a36Sopenharmony_ci
366262306a36Sopenharmony_ci	return ret;
366362306a36Sopenharmony_ci}
366462306a36Sopenharmony_ci
366562306a36Sopenharmony_ciint apply_perf_probe_events(struct perf_probe_event *pevs, int npevs)
366662306a36Sopenharmony_ci{
366762306a36Sopenharmony_ci	int i, ret = 0;
366862306a36Sopenharmony_ci
366962306a36Sopenharmony_ci	/* Loop 2: add all events */
367062306a36Sopenharmony_ci	for (i = 0; i < npevs; i++) {
367162306a36Sopenharmony_ci		ret = __add_probe_trace_events(&pevs[i], pevs[i].tevs,
367262306a36Sopenharmony_ci					       pevs[i].ntevs,
367362306a36Sopenharmony_ci					       probe_conf.force_add);
367462306a36Sopenharmony_ci		if (ret < 0)
367562306a36Sopenharmony_ci			break;
367662306a36Sopenharmony_ci	}
367762306a36Sopenharmony_ci	return ret;
367862306a36Sopenharmony_ci}
367962306a36Sopenharmony_ci
368062306a36Sopenharmony_civoid cleanup_perf_probe_events(struct perf_probe_event *pevs, int npevs)
368162306a36Sopenharmony_ci{
368262306a36Sopenharmony_ci	int i, j;
368362306a36Sopenharmony_ci	struct perf_probe_event *pev;
368462306a36Sopenharmony_ci
368562306a36Sopenharmony_ci	/* Loop 3: cleanup and free trace events  */
368662306a36Sopenharmony_ci	for (i = 0; i < npevs; i++) {
368762306a36Sopenharmony_ci		pev = &pevs[i];
368862306a36Sopenharmony_ci		for (j = 0; j < pevs[i].ntevs; j++)
368962306a36Sopenharmony_ci			clear_probe_trace_event(&pevs[i].tevs[j]);
369062306a36Sopenharmony_ci		zfree(&pevs[i].tevs);
369162306a36Sopenharmony_ci		pevs[i].ntevs = 0;
369262306a36Sopenharmony_ci		nsinfo__zput(pev->nsi);
369362306a36Sopenharmony_ci		clear_perf_probe_event(&pevs[i]);
369462306a36Sopenharmony_ci	}
369562306a36Sopenharmony_ci}
369662306a36Sopenharmony_ci
369762306a36Sopenharmony_ciint add_perf_probe_events(struct perf_probe_event *pevs, int npevs)
369862306a36Sopenharmony_ci{
369962306a36Sopenharmony_ci	int ret;
370062306a36Sopenharmony_ci
370162306a36Sopenharmony_ci	ret = init_probe_symbol_maps(pevs->uprobes);
370262306a36Sopenharmony_ci	if (ret < 0)
370362306a36Sopenharmony_ci		return ret;
370462306a36Sopenharmony_ci
370562306a36Sopenharmony_ci	ret = convert_perf_probe_events(pevs, npevs);
370662306a36Sopenharmony_ci	if (ret == 0)
370762306a36Sopenharmony_ci		ret = apply_perf_probe_events(pevs, npevs);
370862306a36Sopenharmony_ci
370962306a36Sopenharmony_ci	cleanup_perf_probe_events(pevs, npevs);
371062306a36Sopenharmony_ci
371162306a36Sopenharmony_ci	exit_probe_symbol_maps();
371262306a36Sopenharmony_ci	return ret;
371362306a36Sopenharmony_ci}
371462306a36Sopenharmony_ci
371562306a36Sopenharmony_ciint del_perf_probe_events(struct strfilter *filter)
371662306a36Sopenharmony_ci{
371762306a36Sopenharmony_ci	int ret, ret2, ufd = -1, kfd = -1;
371862306a36Sopenharmony_ci	char *str = strfilter__string(filter);
371962306a36Sopenharmony_ci
372062306a36Sopenharmony_ci	if (!str)
372162306a36Sopenharmony_ci		return -EINVAL;
372262306a36Sopenharmony_ci
372362306a36Sopenharmony_ci	/* Get current event names */
372462306a36Sopenharmony_ci	ret = probe_file__open_both(&kfd, &ufd, PF_FL_RW);
372562306a36Sopenharmony_ci	if (ret < 0)
372662306a36Sopenharmony_ci		goto out;
372762306a36Sopenharmony_ci
372862306a36Sopenharmony_ci	ret = probe_file__del_events(kfd, filter);
372962306a36Sopenharmony_ci	if (ret < 0 && ret != -ENOENT)
373062306a36Sopenharmony_ci		goto error;
373162306a36Sopenharmony_ci
373262306a36Sopenharmony_ci	ret2 = probe_file__del_events(ufd, filter);
373362306a36Sopenharmony_ci	if (ret2 < 0 && ret2 != -ENOENT) {
373462306a36Sopenharmony_ci		ret = ret2;
373562306a36Sopenharmony_ci		goto error;
373662306a36Sopenharmony_ci	}
373762306a36Sopenharmony_ci	ret = 0;
373862306a36Sopenharmony_ci
373962306a36Sopenharmony_cierror:
374062306a36Sopenharmony_ci	if (kfd >= 0)
374162306a36Sopenharmony_ci		close(kfd);
374262306a36Sopenharmony_ci	if (ufd >= 0)
374362306a36Sopenharmony_ci		close(ufd);
374462306a36Sopenharmony_ciout:
374562306a36Sopenharmony_ci	free(str);
374662306a36Sopenharmony_ci
374762306a36Sopenharmony_ci	return ret;
374862306a36Sopenharmony_ci}
374962306a36Sopenharmony_ci
375062306a36Sopenharmony_ciint show_available_funcs(const char *target, struct nsinfo *nsi,
375162306a36Sopenharmony_ci			 struct strfilter *_filter, bool user)
375262306a36Sopenharmony_ci{
375362306a36Sopenharmony_ci	struct map *map;
375462306a36Sopenharmony_ci	struct dso *dso;
375562306a36Sopenharmony_ci	int ret;
375662306a36Sopenharmony_ci
375762306a36Sopenharmony_ci	ret = init_probe_symbol_maps(user);
375862306a36Sopenharmony_ci	if (ret < 0)
375962306a36Sopenharmony_ci		return ret;
376062306a36Sopenharmony_ci
376162306a36Sopenharmony_ci	/* Get a symbol map */
376262306a36Sopenharmony_ci	map = get_target_map(target, nsi, user);
376362306a36Sopenharmony_ci	if (!map) {
376462306a36Sopenharmony_ci		pr_err("Failed to get a map for %s\n", (target) ? : "kernel");
376562306a36Sopenharmony_ci		return -EINVAL;
376662306a36Sopenharmony_ci	}
376762306a36Sopenharmony_ci
376862306a36Sopenharmony_ci	ret = map__load(map);
376962306a36Sopenharmony_ci	if (ret) {
377062306a36Sopenharmony_ci		if (ret == -2) {
377162306a36Sopenharmony_ci			char *str = strfilter__string(_filter);
377262306a36Sopenharmony_ci			pr_err("Failed to find symbols matched to \"%s\"\n",
377362306a36Sopenharmony_ci			       str);
377462306a36Sopenharmony_ci			free(str);
377562306a36Sopenharmony_ci		} else
377662306a36Sopenharmony_ci			pr_err("Failed to load symbols in %s\n",
377762306a36Sopenharmony_ci			       (target) ? : "kernel");
377862306a36Sopenharmony_ci		goto end;
377962306a36Sopenharmony_ci	}
378062306a36Sopenharmony_ci	dso = map__dso(map);
378162306a36Sopenharmony_ci	dso__sort_by_name(dso);
378262306a36Sopenharmony_ci
378362306a36Sopenharmony_ci	/* Show all (filtered) symbols */
378462306a36Sopenharmony_ci	setup_pager();
378562306a36Sopenharmony_ci
378662306a36Sopenharmony_ci	for (size_t i = 0; i < dso->symbol_names_len; i++) {
378762306a36Sopenharmony_ci		struct symbol *pos = dso->symbol_names[i];
378862306a36Sopenharmony_ci
378962306a36Sopenharmony_ci		if (strfilter__compare(_filter, pos->name))
379062306a36Sopenharmony_ci			printf("%s\n", pos->name);
379162306a36Sopenharmony_ci	}
379262306a36Sopenharmony_ciend:
379362306a36Sopenharmony_ci	map__put(map);
379462306a36Sopenharmony_ci	exit_probe_symbol_maps();
379562306a36Sopenharmony_ci
379662306a36Sopenharmony_ci	return ret;
379762306a36Sopenharmony_ci}
379862306a36Sopenharmony_ci
379962306a36Sopenharmony_ciint copy_to_probe_trace_arg(struct probe_trace_arg *tvar,
380062306a36Sopenharmony_ci			    struct perf_probe_arg *pvar)
380162306a36Sopenharmony_ci{
380262306a36Sopenharmony_ci	tvar->value = strdup(pvar->var);
380362306a36Sopenharmony_ci	if (tvar->value == NULL)
380462306a36Sopenharmony_ci		return -ENOMEM;
380562306a36Sopenharmony_ci	if (pvar->type) {
380662306a36Sopenharmony_ci		tvar->type = strdup(pvar->type);
380762306a36Sopenharmony_ci		if (tvar->type == NULL)
380862306a36Sopenharmony_ci			return -ENOMEM;
380962306a36Sopenharmony_ci	}
381062306a36Sopenharmony_ci	if (pvar->name) {
381162306a36Sopenharmony_ci		tvar->name = strdup(pvar->name);
381262306a36Sopenharmony_ci		if (tvar->name == NULL)
381362306a36Sopenharmony_ci			return -ENOMEM;
381462306a36Sopenharmony_ci	} else
381562306a36Sopenharmony_ci		tvar->name = NULL;
381662306a36Sopenharmony_ci	return 0;
381762306a36Sopenharmony_ci}
3818