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