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