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> 441d037ca1SIrina Tirdea #include "trace-event.h" /* For __maybe_unused */ 4550656eecSMasami Hiramatsu #include "probe-event.h" 464235b045SMasami Hiramatsu #include "probe-finder.h" 47225466f1SSrikar Dronamraju #include "session.h" 4850656eecSMasami Hiramatsu 4950656eecSMasami Hiramatsu #define MAX_CMDLEN 256 5050656eecSMasami Hiramatsu #define PERFPROBE_GROUP "probe" 5150656eecSMasami Hiramatsu 52f4d7da49SMasami Hiramatsu bool probe_event_dry_run; /* Dry run flag */ 53f4d7da49SMasami Hiramatsu 54146a1439SMasami Hiramatsu #define semantic_error(msg ...) pr_err("Semantic error :" msg) 5550656eecSMasami Hiramatsu 564de189feSMasami Hiramatsu /* If there is no space to write, returns -E2BIG. */ 574de189feSMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...) 5884988450SMasami Hiramatsu __attribute__((format(printf, 3, 4))); 5984988450SMasami Hiramatsu 6084988450SMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...) 614de189feSMasami Hiramatsu { 624de189feSMasami Hiramatsu int ret; 634de189feSMasami Hiramatsu va_list ap; 644de189feSMasami Hiramatsu va_start(ap, format); 654de189feSMasami Hiramatsu ret = vsnprintf(str, size, format, ap); 664de189feSMasami Hiramatsu va_end(ap); 674de189feSMasami Hiramatsu if (ret >= (int)size) 684de189feSMasami Hiramatsu ret = -E2BIG; 694de189feSMasami Hiramatsu return ret; 704de189feSMasami Hiramatsu } 714de189feSMasami Hiramatsu 724b4da7f7SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 73981d05adSMasami Hiramatsu static void clear_probe_trace_event(struct probe_trace_event *tev); 74ee45b6c2SMasami Hiramatsu static struct machine *host_machine; 75e0faa8d3SMasami Hiramatsu 76469b9b88SMasami Hiramatsu /* Initialize symbol maps and path of vmlinux/modules */ 77ee45b6c2SMasami Hiramatsu static int init_symbol_maps(bool user_only) 78e0faa8d3SMasami Hiramatsu { 79146a1439SMasami Hiramatsu int ret; 80146a1439SMasami Hiramatsu 81e0faa8d3SMasami Hiramatsu symbol_conf.sort_by_name = true; 820a7e6d1bSNamhyung Kim ret = symbol__init(NULL); 83146a1439SMasami Hiramatsu if (ret < 0) { 84146a1439SMasami Hiramatsu pr_debug("Failed to init symbol map.\n"); 85146a1439SMasami Hiramatsu goto out; 86146a1439SMasami Hiramatsu } 87e0faa8d3SMasami Hiramatsu 88ee45b6c2SMasami Hiramatsu if (host_machine || user_only) /* already initialized */ 89ee45b6c2SMasami Hiramatsu return 0; 90d28c6223SArnaldo Carvalho de Melo 91ee45b6c2SMasami Hiramatsu if (symbol_conf.vmlinux_name) 92ee45b6c2SMasami Hiramatsu pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name); 93ee45b6c2SMasami Hiramatsu 94ee45b6c2SMasami Hiramatsu host_machine = machine__new_host(); 95ee45b6c2SMasami Hiramatsu if (!host_machine) { 96ee45b6c2SMasami Hiramatsu pr_debug("machine__new_host() failed.\n"); 97ee45b6c2SMasami Hiramatsu symbol__exit(); 98ee45b6c2SMasami Hiramatsu ret = -1; 99469b9b88SMasami Hiramatsu } 100146a1439SMasami Hiramatsu out: 101146a1439SMasami Hiramatsu if (ret < 0) 102146a1439SMasami Hiramatsu pr_warning("Failed to init vmlinux path.\n"); 103146a1439SMasami Hiramatsu return ret; 104e0faa8d3SMasami Hiramatsu } 105e0faa8d3SMasami Hiramatsu 106ee45b6c2SMasami Hiramatsu static void exit_symbol_maps(void) 107ee45b6c2SMasami Hiramatsu { 108ee45b6c2SMasami Hiramatsu if (host_machine) { 109ee45b6c2SMasami Hiramatsu machine__delete(host_machine); 110ee45b6c2SMasami Hiramatsu host_machine = NULL; 111ee45b6c2SMasami Hiramatsu } 112ee45b6c2SMasami Hiramatsu symbol__exit(); 113ee45b6c2SMasami Hiramatsu } 114ee45b6c2SMasami Hiramatsu 115469b9b88SMasami Hiramatsu static struct symbol *__find_kernel_function_by_name(const char *name, 116469b9b88SMasami Hiramatsu struct map **mapp) 117e0faa8d3SMasami Hiramatsu { 118ee45b6c2SMasami Hiramatsu return machine__find_kernel_function_by_name(host_machine, name, mapp, 119469b9b88SMasami Hiramatsu NULL); 120e0faa8d3SMasami Hiramatsu } 121469b9b88SMasami Hiramatsu 1228f33f7deSMasami Hiramatsu static struct symbol *__find_kernel_function(u64 addr, struct map **mapp) 1238f33f7deSMasami Hiramatsu { 1248f33f7deSMasami Hiramatsu return machine__find_kernel_function(host_machine, addr, mapp, NULL); 1258f33f7deSMasami Hiramatsu } 1268f33f7deSMasami Hiramatsu 1278f33f7deSMasami Hiramatsu static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void) 1288f33f7deSMasami Hiramatsu { 1298f33f7deSMasami Hiramatsu /* kmap->ref_reloc_sym should be set if host_machine is initialized */ 1308f33f7deSMasami Hiramatsu struct kmap *kmap; 1318f33f7deSMasami Hiramatsu 1328f33f7deSMasami Hiramatsu if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0) 1338f33f7deSMasami Hiramatsu return NULL; 1348f33f7deSMasami Hiramatsu 1358f33f7deSMasami Hiramatsu kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]); 1368f33f7deSMasami Hiramatsu return kmap->ref_reloc_sym; 1378f33f7deSMasami Hiramatsu } 1388f33f7deSMasami Hiramatsu 1398f33f7deSMasami Hiramatsu static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc) 1408f33f7deSMasami Hiramatsu { 1418f33f7deSMasami Hiramatsu struct ref_reloc_sym *reloc_sym; 1428f33f7deSMasami Hiramatsu struct symbol *sym; 1438f33f7deSMasami Hiramatsu struct map *map; 1448f33f7deSMasami Hiramatsu 1458f33f7deSMasami Hiramatsu /* ref_reloc_sym is just a label. Need a special fix*/ 1468f33f7deSMasami Hiramatsu reloc_sym = kernel_get_ref_reloc_sym(); 1478f33f7deSMasami Hiramatsu if (reloc_sym && strcmp(name, reloc_sym->name) == 0) 1488f33f7deSMasami Hiramatsu return (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr; 1498f33f7deSMasami Hiramatsu else { 1508f33f7deSMasami Hiramatsu sym = __find_kernel_function_by_name(name, &map); 1518f33f7deSMasami Hiramatsu if (sym) 1528f33f7deSMasami Hiramatsu return map->unmap_ip(map, sym->start) - 1538f33f7deSMasami Hiramatsu (reloc) ? 0 : map->reloc; 1548f33f7deSMasami Hiramatsu } 1558f33f7deSMasami Hiramatsu return 0; 1568f33f7deSMasami Hiramatsu } 1578f33f7deSMasami Hiramatsu 158e80711caSMasami Hiramatsu static struct map *kernel_get_module_map(const char *module) 159e80711caSMasami Hiramatsu { 160e80711caSMasami Hiramatsu struct rb_node *nd; 161ee45b6c2SMasami Hiramatsu struct map_groups *grp = &host_machine->kmaps; 162e80711caSMasami Hiramatsu 16314a8fd7cSMasami Hiramatsu /* A file path -- this is an offline module */ 16414a8fd7cSMasami Hiramatsu if (module && strchr(module, '/')) 165ee45b6c2SMasami Hiramatsu return machine__new_module(host_machine, 0, module); 16614a8fd7cSMasami Hiramatsu 167e80711caSMasami Hiramatsu if (!module) 168e80711caSMasami Hiramatsu module = "kernel"; 169e80711caSMasami Hiramatsu 170e80711caSMasami Hiramatsu for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { 171e80711caSMasami Hiramatsu struct map *pos = rb_entry(nd, struct map, rb_node); 172e80711caSMasami Hiramatsu if (strncmp(pos->dso->short_name + 1, module, 173e80711caSMasami Hiramatsu pos->dso->short_name_len - 2) == 0) { 174e80711caSMasami Hiramatsu return pos; 175e80711caSMasami Hiramatsu } 176e80711caSMasami Hiramatsu } 177e80711caSMasami Hiramatsu return NULL; 178e80711caSMasami Hiramatsu } 179e80711caSMasami Hiramatsu 180e80711caSMasami Hiramatsu static struct dso *kernel_get_module_dso(const char *module) 181469b9b88SMasami Hiramatsu { 182469b9b88SMasami Hiramatsu struct dso *dso; 183fd930ff9SFranck Bui-Huu struct map *map; 184fd930ff9SFranck Bui-Huu const char *vmlinux_name; 185469b9b88SMasami Hiramatsu 186469b9b88SMasami Hiramatsu if (module) { 187ee45b6c2SMasami Hiramatsu list_for_each_entry(dso, &host_machine->kernel_dsos, node) { 188469b9b88SMasami Hiramatsu if (strncmp(dso->short_name + 1, module, 189469b9b88SMasami Hiramatsu dso->short_name_len - 2) == 0) 190469b9b88SMasami Hiramatsu goto found; 191469b9b88SMasami Hiramatsu } 192469b9b88SMasami Hiramatsu pr_debug("Failed to find module %s.\n", module); 193469b9b88SMasami Hiramatsu return NULL; 194fd930ff9SFranck Bui-Huu } 195fd930ff9SFranck Bui-Huu 196ee45b6c2SMasami Hiramatsu map = host_machine->vmlinux_maps[MAP__FUNCTION]; 197fd930ff9SFranck Bui-Huu dso = map->dso; 198fd930ff9SFranck Bui-Huu 199fd930ff9SFranck Bui-Huu vmlinux_name = symbol_conf.vmlinux_name; 200fd930ff9SFranck Bui-Huu if (vmlinux_name) { 2015230fb7dSArnaldo Carvalho de Melo if (dso__load_vmlinux(dso, map, vmlinux_name, false, NULL) <= 0) 202fd930ff9SFranck Bui-Huu return NULL; 203469b9b88SMasami Hiramatsu } else { 204c3a34e06SFranck Bui-Huu if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { 205469b9b88SMasami Hiramatsu pr_debug("Failed to load kernel map.\n"); 206469b9b88SMasami Hiramatsu return NULL; 207469b9b88SMasami Hiramatsu } 208469b9b88SMasami Hiramatsu } 209469b9b88SMasami Hiramatsu found: 210e80711caSMasami Hiramatsu return dso; 211e80711caSMasami Hiramatsu } 212e80711caSMasami Hiramatsu 213e80711caSMasami Hiramatsu const char *kernel_get_module_path(const char *module) 214e80711caSMasami Hiramatsu { 215e80711caSMasami Hiramatsu struct dso *dso = kernel_get_module_dso(module); 216e80711caSMasami Hiramatsu return (dso) ? dso->long_name : NULL; 217469b9b88SMasami Hiramatsu } 218469b9b88SMasami Hiramatsu 219fb7345bbSMasami Hiramatsu static int convert_exec_to_group(const char *exec, char **result) 220fb7345bbSMasami Hiramatsu { 221fb7345bbSMasami Hiramatsu char *ptr1, *ptr2, *exec_copy; 222fb7345bbSMasami Hiramatsu char buf[64]; 223fb7345bbSMasami Hiramatsu int ret; 224fb7345bbSMasami Hiramatsu 225fb7345bbSMasami Hiramatsu exec_copy = strdup(exec); 226fb7345bbSMasami Hiramatsu if (!exec_copy) 227fb7345bbSMasami Hiramatsu return -ENOMEM; 228fb7345bbSMasami Hiramatsu 229fb7345bbSMasami Hiramatsu ptr1 = basename(exec_copy); 230fb7345bbSMasami Hiramatsu if (!ptr1) { 231fb7345bbSMasami Hiramatsu ret = -EINVAL; 232fb7345bbSMasami Hiramatsu goto out; 233fb7345bbSMasami Hiramatsu } 234fb7345bbSMasami Hiramatsu 235fb7345bbSMasami Hiramatsu ptr2 = strpbrk(ptr1, "-._"); 236fb7345bbSMasami Hiramatsu if (ptr2) 237fb7345bbSMasami Hiramatsu *ptr2 = '\0'; 238fb7345bbSMasami Hiramatsu ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1); 239fb7345bbSMasami Hiramatsu if (ret < 0) 240fb7345bbSMasami Hiramatsu goto out; 241fb7345bbSMasami Hiramatsu 242fb7345bbSMasami Hiramatsu *result = strdup(buf); 243fb7345bbSMasami Hiramatsu ret = *result ? 0 : -ENOMEM; 244fb7345bbSMasami Hiramatsu 245fb7345bbSMasami Hiramatsu out: 246fb7345bbSMasami Hiramatsu free(exec_copy); 247fb7345bbSMasami Hiramatsu return ret; 248fb7345bbSMasami Hiramatsu } 249fb7345bbSMasami Hiramatsu 250eb948e50SMasami Hiramatsu static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) 251eb948e50SMasami Hiramatsu { 252eb948e50SMasami Hiramatsu int i; 253eb948e50SMasami Hiramatsu 254eb948e50SMasami Hiramatsu for (i = 0; i < ntevs; i++) 255eb948e50SMasami Hiramatsu clear_probe_trace_event(tevs + i); 256eb948e50SMasami Hiramatsu } 257eb948e50SMasami Hiramatsu 25889fe808aSIngo Molnar #ifdef HAVE_DWARF_SUPPORT 259a15ad2f5SMasami Hiramatsu 260ff741783SMasami Hiramatsu /* Open new debuginfo of given module */ 26192561cb7SMasami Hiramatsu static struct debuginfo *open_debuginfo(const char *module, bool silent) 262469b9b88SMasami Hiramatsu { 263a15ad2f5SMasami Hiramatsu const char *path = module; 26492561cb7SMasami Hiramatsu struct debuginfo *ret; 26514a8fd7cSMasami Hiramatsu 266a15ad2f5SMasami Hiramatsu if (!module || !strchr(module, '/')) { 26714a8fd7cSMasami Hiramatsu path = kernel_get_module_path(module); 268469b9b88SMasami Hiramatsu if (!path) { 26992561cb7SMasami Hiramatsu if (!silent) 2700e43e5d2SMasami Hiramatsu pr_err("Failed to find path of %s module.\n", 2710e43e5d2SMasami Hiramatsu module ?: "kernel"); 272ff741783SMasami Hiramatsu return NULL; 273469b9b88SMasami Hiramatsu } 27414a8fd7cSMasami Hiramatsu } 27592561cb7SMasami Hiramatsu ret = debuginfo__new(path); 27692561cb7SMasami Hiramatsu if (!ret && !silent) { 27792561cb7SMasami Hiramatsu pr_warning("The %s file has no debug information.\n", path); 27892561cb7SMasami Hiramatsu if (!module || !strtailcmp(path, ".ko")) 27992561cb7SMasami Hiramatsu pr_warning("Rebuild with CONFIG_DEBUG_INFO=y, "); 28092561cb7SMasami Hiramatsu else 28192561cb7SMasami Hiramatsu pr_warning("Rebuild with -g, "); 28292561cb7SMasami Hiramatsu pr_warning("or install an appropriate debuginfo package.\n"); 283e0faa8d3SMasami Hiramatsu } 28492561cb7SMasami Hiramatsu return ret; 28592561cb7SMasami Hiramatsu } 28692561cb7SMasami Hiramatsu 2874b4da7f7SMasami Hiramatsu 28899ca4233SMasami Hiramatsu static int get_text_start_address(const char *exec, unsigned long *address) 28999ca4233SMasami Hiramatsu { 29099ca4233SMasami Hiramatsu Elf *elf; 29199ca4233SMasami Hiramatsu GElf_Ehdr ehdr; 29299ca4233SMasami Hiramatsu GElf_Shdr shdr; 29399ca4233SMasami Hiramatsu int fd, ret = -ENOENT; 29499ca4233SMasami Hiramatsu 29599ca4233SMasami Hiramatsu fd = open(exec, O_RDONLY); 29699ca4233SMasami Hiramatsu if (fd < 0) 29799ca4233SMasami Hiramatsu return -errno; 29899ca4233SMasami Hiramatsu 29999ca4233SMasami Hiramatsu elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 30099ca4233SMasami Hiramatsu if (elf == NULL) 30199ca4233SMasami Hiramatsu return -EINVAL; 30299ca4233SMasami Hiramatsu 30399ca4233SMasami Hiramatsu if (gelf_getehdr(elf, &ehdr) == NULL) 30499ca4233SMasami Hiramatsu goto out; 30599ca4233SMasami Hiramatsu 30699ca4233SMasami Hiramatsu if (!elf_section_by_name(elf, &ehdr, &shdr, ".text", NULL)) 30799ca4233SMasami Hiramatsu goto out; 30899ca4233SMasami Hiramatsu 30999ca4233SMasami Hiramatsu *address = shdr.sh_addr - shdr.sh_offset; 31099ca4233SMasami Hiramatsu ret = 0; 31199ca4233SMasami Hiramatsu out: 31299ca4233SMasami Hiramatsu elf_end(elf); 31399ca4233SMasami Hiramatsu return ret; 31499ca4233SMasami Hiramatsu } 31599ca4233SMasami Hiramatsu 3165a6f6314SMasami Hiramatsu /* 3175a6f6314SMasami Hiramatsu * Convert trace point to probe point with debuginfo 3185a6f6314SMasami Hiramatsu */ 3195a6f6314SMasami Hiramatsu static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp, 3205a6f6314SMasami Hiramatsu struct perf_probe_point *pp, 3215a6f6314SMasami Hiramatsu bool is_kprobe) 3225a6f6314SMasami Hiramatsu { 3235a6f6314SMasami Hiramatsu struct debuginfo *dinfo = NULL; 3245a6f6314SMasami Hiramatsu unsigned long stext = 0; 3255a6f6314SMasami Hiramatsu u64 addr = tp->address; 3265a6f6314SMasami Hiramatsu int ret = -ENOENT; 3275a6f6314SMasami Hiramatsu 3285a6f6314SMasami Hiramatsu /* convert the address to dwarf address */ 3295a6f6314SMasami Hiramatsu if (!is_kprobe) { 3305a6f6314SMasami Hiramatsu if (!addr) { 3315a6f6314SMasami Hiramatsu ret = -EINVAL; 3325a6f6314SMasami Hiramatsu goto error; 3335a6f6314SMasami Hiramatsu } 3345a6f6314SMasami Hiramatsu ret = get_text_start_address(tp->module, &stext); 3355a6f6314SMasami Hiramatsu if (ret < 0) 3365a6f6314SMasami Hiramatsu goto error; 3375a6f6314SMasami Hiramatsu addr += stext; 3385a6f6314SMasami Hiramatsu } else { 3395a6f6314SMasami Hiramatsu addr = kernel_get_symbol_address_by_name(tp->symbol, false); 3405a6f6314SMasami Hiramatsu if (addr == 0) 3415a6f6314SMasami Hiramatsu goto error; 3425a6f6314SMasami Hiramatsu addr += tp->offset; 3435a6f6314SMasami Hiramatsu } 3445a6f6314SMasami Hiramatsu 3455a6f6314SMasami Hiramatsu pr_debug("try to find information at %" PRIx64 " in %s\n", addr, 3465a6f6314SMasami Hiramatsu tp->module ? : "kernel"); 3475a6f6314SMasami Hiramatsu 34892561cb7SMasami Hiramatsu dinfo = open_debuginfo(tp->module, verbose == 0); 3495a6f6314SMasami Hiramatsu if (dinfo) { 3505a6f6314SMasami Hiramatsu ret = debuginfo__find_probe_point(dinfo, 3515a6f6314SMasami Hiramatsu (unsigned long)addr, pp); 3525a6f6314SMasami Hiramatsu debuginfo__delete(dinfo); 35392561cb7SMasami Hiramatsu } else 3545a6f6314SMasami Hiramatsu ret = -ENOENT; 3555a6f6314SMasami Hiramatsu 3565a6f6314SMasami Hiramatsu if (ret > 0) { 3575a6f6314SMasami Hiramatsu pp->retprobe = tp->retprobe; 3585a6f6314SMasami Hiramatsu return 0; 3595a6f6314SMasami Hiramatsu } 3605a6f6314SMasami Hiramatsu error: 3615a6f6314SMasami Hiramatsu pr_debug("Failed to find corresponding probes from debuginfo.\n"); 3625a6f6314SMasami Hiramatsu return ret ? : -ENOENT; 3635a6f6314SMasami Hiramatsu } 3645a6f6314SMasami Hiramatsu 365fb7345bbSMasami Hiramatsu static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, 366fb7345bbSMasami Hiramatsu int ntevs, const char *exec) 367fb7345bbSMasami Hiramatsu { 368fb7345bbSMasami Hiramatsu int i, ret = 0; 369eb948e50SMasami Hiramatsu unsigned long stext = 0; 370fb7345bbSMasami Hiramatsu 371fb7345bbSMasami Hiramatsu if (!exec) 372fb7345bbSMasami Hiramatsu return 0; 373fb7345bbSMasami Hiramatsu 374fb7345bbSMasami Hiramatsu ret = get_text_start_address(exec, &stext); 375fb7345bbSMasami Hiramatsu if (ret < 0) 376fb7345bbSMasami Hiramatsu return ret; 377fb7345bbSMasami Hiramatsu 378fb7345bbSMasami Hiramatsu for (i = 0; i < ntevs && ret >= 0; i++) { 379981a2379SMasami Hiramatsu /* point.address is the addres of point.symbol + point.offset */ 380eb948e50SMasami Hiramatsu tevs[i].point.address -= stext; 381fb7345bbSMasami Hiramatsu tevs[i].point.module = strdup(exec); 382eb948e50SMasami Hiramatsu if (!tevs[i].point.module) { 383fb7345bbSMasami Hiramatsu ret = -ENOMEM; 384fb7345bbSMasami Hiramatsu break; 385fb7345bbSMasami Hiramatsu } 386fb7345bbSMasami Hiramatsu tevs[i].uprobes = true; 387fb7345bbSMasami Hiramatsu } 388fb7345bbSMasami Hiramatsu 389fb7345bbSMasami Hiramatsu return ret; 390fb7345bbSMasami Hiramatsu } 391fb7345bbSMasami Hiramatsu 392190b57fcSMasami Hiramatsu static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, 393190b57fcSMasami Hiramatsu int ntevs, const char *module) 394190b57fcSMasami Hiramatsu { 39514a8fd7cSMasami Hiramatsu int i, ret = 0; 39614a8fd7cSMasami Hiramatsu char *tmp; 39714a8fd7cSMasami Hiramatsu 39814a8fd7cSMasami Hiramatsu if (!module) 39914a8fd7cSMasami Hiramatsu return 0; 40014a8fd7cSMasami Hiramatsu 40114a8fd7cSMasami Hiramatsu tmp = strrchr(module, '/'); 40214a8fd7cSMasami Hiramatsu if (tmp) { 40314a8fd7cSMasami Hiramatsu /* This is a module path -- get the module name */ 40414a8fd7cSMasami Hiramatsu module = strdup(tmp + 1); 40514a8fd7cSMasami Hiramatsu if (!module) 40614a8fd7cSMasami Hiramatsu return -ENOMEM; 40714a8fd7cSMasami Hiramatsu tmp = strchr(module, '.'); 40814a8fd7cSMasami Hiramatsu if (tmp) 40914a8fd7cSMasami Hiramatsu *tmp = '\0'; 41014a8fd7cSMasami Hiramatsu tmp = (char *)module; /* For free() */ 41114a8fd7cSMasami Hiramatsu } 41214a8fd7cSMasami Hiramatsu 413190b57fcSMasami Hiramatsu for (i = 0; i < ntevs; i++) { 414190b57fcSMasami Hiramatsu tevs[i].point.module = strdup(module); 41514a8fd7cSMasami Hiramatsu if (!tevs[i].point.module) { 41614a8fd7cSMasami Hiramatsu ret = -ENOMEM; 41714a8fd7cSMasami Hiramatsu break; 418190b57fcSMasami Hiramatsu } 41914a8fd7cSMasami Hiramatsu } 42014a8fd7cSMasami Hiramatsu 42114a8fd7cSMasami Hiramatsu free(tmp); 42214a8fd7cSMasami Hiramatsu return ret; 423190b57fcSMasami Hiramatsu } 424190b57fcSMasami Hiramatsu 425dfef99cdSMasami Hiramatsu /* Post processing the probe events */ 426dfef99cdSMasami Hiramatsu static int post_process_probe_trace_events(struct probe_trace_event *tevs, 427dfef99cdSMasami Hiramatsu int ntevs, const char *module, 428dfef99cdSMasami Hiramatsu bool uprobe) 429dfef99cdSMasami Hiramatsu { 430dfef99cdSMasami Hiramatsu struct ref_reloc_sym *reloc_sym; 431dfef99cdSMasami Hiramatsu char *tmp; 432dfef99cdSMasami Hiramatsu int i; 433dfef99cdSMasami Hiramatsu 434dfef99cdSMasami Hiramatsu if (uprobe) 435dfef99cdSMasami Hiramatsu return add_exec_to_probe_trace_events(tevs, ntevs, module); 436dfef99cdSMasami Hiramatsu 437dfef99cdSMasami Hiramatsu /* Note that currently ref_reloc_sym based probe is not for drivers */ 438dfef99cdSMasami Hiramatsu if (module) 439dfef99cdSMasami Hiramatsu return add_module_to_probe_trace_events(tevs, ntevs, module); 440dfef99cdSMasami Hiramatsu 4418f33f7deSMasami Hiramatsu reloc_sym = kernel_get_ref_reloc_sym(); 442dfef99cdSMasami Hiramatsu if (!reloc_sym) { 443dfef99cdSMasami Hiramatsu pr_warning("Relocated base symbol is not found!\n"); 444dfef99cdSMasami Hiramatsu return -EINVAL; 445dfef99cdSMasami Hiramatsu } 446dfef99cdSMasami Hiramatsu 447dfef99cdSMasami Hiramatsu for (i = 0; i < ntevs; i++) { 448dfef99cdSMasami Hiramatsu if (tevs[i].point.address) { 449dfef99cdSMasami Hiramatsu tmp = strdup(reloc_sym->name); 450dfef99cdSMasami Hiramatsu if (!tmp) 451dfef99cdSMasami Hiramatsu return -ENOMEM; 452dfef99cdSMasami Hiramatsu free(tevs[i].point.symbol); 453dfef99cdSMasami Hiramatsu tevs[i].point.symbol = tmp; 454dfef99cdSMasami Hiramatsu tevs[i].point.offset = tevs[i].point.address - 455dfef99cdSMasami Hiramatsu reloc_sym->unrelocated_addr; 456dfef99cdSMasami Hiramatsu } 457dfef99cdSMasami Hiramatsu } 458dfef99cdSMasami Hiramatsu return 0; 459dfef99cdSMasami Hiramatsu } 460dfef99cdSMasami Hiramatsu 4614b4da7f7SMasami Hiramatsu /* Try to find perf_probe_event with debuginfo */ 4620e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 4630e60836bSSrikar Dronamraju struct probe_trace_event **tevs, 4644eced234SSrikar Dronamraju int max_tevs, const char *target) 4654b4da7f7SMasami Hiramatsu { 4664b4da7f7SMasami Hiramatsu bool need_dwarf = perf_probe_event_need_dwarf(pev); 467225466f1SSrikar Dronamraju struct debuginfo *dinfo; 468190b57fcSMasami Hiramatsu int ntevs, ret = 0; 4694b4da7f7SMasami Hiramatsu 47092561cb7SMasami Hiramatsu dinfo = open_debuginfo(target, !need_dwarf); 471225466f1SSrikar Dronamraju 472ff741783SMasami Hiramatsu if (!dinfo) { 47392561cb7SMasami Hiramatsu if (need_dwarf) 474ff741783SMasami Hiramatsu return -ENOENT; 475ff741783SMasami Hiramatsu pr_debug("Could not open debuginfo. Try to use symbols.\n"); 4764b4da7f7SMasami Hiramatsu return 0; 4774b4da7f7SMasami Hiramatsu } 4784b4da7f7SMasami Hiramatsu 479dfef99cdSMasami Hiramatsu pr_debug("Try to find probe point from debuginfo.\n"); 480ff741783SMasami Hiramatsu /* Searching trace events corresponding to a probe event */ 481ff741783SMasami Hiramatsu ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs); 482ff741783SMasami Hiramatsu 483ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 4844b4da7f7SMasami Hiramatsu 485146a1439SMasami Hiramatsu if (ntevs > 0) { /* Succeeded to find trace events */ 486dfef99cdSMasami Hiramatsu pr_debug("Found %d probe_trace_events.\n", ntevs); 487dfef99cdSMasami Hiramatsu ret = post_process_probe_trace_events(*tevs, ntevs, 488dfef99cdSMasami Hiramatsu target, pev->uprobes); 489981d05adSMasami Hiramatsu if (ret < 0) { 490981d05adSMasami Hiramatsu clear_probe_trace_events(*tevs, ntevs); 491981d05adSMasami Hiramatsu zfree(tevs); 492981d05adSMasami Hiramatsu } 493190b57fcSMasami Hiramatsu return ret < 0 ? ret : ntevs; 494146a1439SMasami Hiramatsu } 4954b4da7f7SMasami Hiramatsu 496146a1439SMasami Hiramatsu if (ntevs == 0) { /* No error but failed to find probe point. */ 497146a1439SMasami Hiramatsu pr_warning("Probe point '%s' not found.\n", 4984b4da7f7SMasami Hiramatsu synthesize_perf_probe_point(&pev->point)); 499146a1439SMasami Hiramatsu return -ENOENT; 500146a1439SMasami Hiramatsu } 501146a1439SMasami Hiramatsu /* Error path : ntevs < 0 */ 50215eca306SMasami Hiramatsu pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); 50315eca306SMasami Hiramatsu if (ntevs == -EBADF) { 50415eca306SMasami Hiramatsu pr_warning("Warning: No dwarf info found in the vmlinux - " 50515eca306SMasami Hiramatsu "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); 50615eca306SMasami Hiramatsu if (!need_dwarf) { 5070e43e5d2SMasami Hiramatsu pr_debug("Trying to use symbols.\n"); 5084b4da7f7SMasami Hiramatsu return 0; 5094b4da7f7SMasami Hiramatsu } 51015eca306SMasami Hiramatsu } 51115eca306SMasami Hiramatsu return ntevs; 51215eca306SMasami Hiramatsu } 5134b4da7f7SMasami Hiramatsu 5147cf0b79eSMasami Hiramatsu /* 5157cf0b79eSMasami Hiramatsu * Find a src file from a DWARF tag path. Prepend optional source path prefix 5167cf0b79eSMasami Hiramatsu * and chop off leading directories that do not exist. Result is passed back as 5177cf0b79eSMasami Hiramatsu * a newly allocated path on success. 5187cf0b79eSMasami Hiramatsu * Return 0 if file was found and readable, -errno otherwise. 5197cf0b79eSMasami Hiramatsu */ 5206a330a3cSMasami Hiramatsu static int get_real_path(const char *raw_path, const char *comp_dir, 5216a330a3cSMasami Hiramatsu char **new_path) 5227cf0b79eSMasami Hiramatsu { 5236a330a3cSMasami Hiramatsu const char *prefix = symbol_conf.source_prefix; 5246a330a3cSMasami Hiramatsu 5256a330a3cSMasami Hiramatsu if (!prefix) { 5266a330a3cSMasami Hiramatsu if (raw_path[0] != '/' && comp_dir) 5276a330a3cSMasami Hiramatsu /* If not an absolute path, try to use comp_dir */ 5286a330a3cSMasami Hiramatsu prefix = comp_dir; 5296a330a3cSMasami Hiramatsu else { 5307cf0b79eSMasami Hiramatsu if (access(raw_path, R_OK) == 0) { 5317cf0b79eSMasami Hiramatsu *new_path = strdup(raw_path); 5327cf0b79eSMasami Hiramatsu return 0; 5337cf0b79eSMasami Hiramatsu } else 5347cf0b79eSMasami Hiramatsu return -errno; 5357cf0b79eSMasami Hiramatsu } 5366a330a3cSMasami Hiramatsu } 5377cf0b79eSMasami Hiramatsu 5386a330a3cSMasami Hiramatsu *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); 5397cf0b79eSMasami Hiramatsu if (!*new_path) 5407cf0b79eSMasami Hiramatsu return -ENOMEM; 5417cf0b79eSMasami Hiramatsu 5427cf0b79eSMasami Hiramatsu for (;;) { 5436a330a3cSMasami Hiramatsu sprintf(*new_path, "%s/%s", prefix, raw_path); 5447cf0b79eSMasami Hiramatsu 5457cf0b79eSMasami Hiramatsu if (access(*new_path, R_OK) == 0) 5467cf0b79eSMasami Hiramatsu return 0; 5477cf0b79eSMasami Hiramatsu 5486a330a3cSMasami Hiramatsu if (!symbol_conf.source_prefix) 5496a330a3cSMasami Hiramatsu /* In case of searching comp_dir, don't retry */ 5506a330a3cSMasami Hiramatsu return -errno; 5516a330a3cSMasami Hiramatsu 5527cf0b79eSMasami Hiramatsu switch (errno) { 5537cf0b79eSMasami Hiramatsu case ENAMETOOLONG: 5547cf0b79eSMasami Hiramatsu case ENOENT: 5557cf0b79eSMasami Hiramatsu case EROFS: 5567cf0b79eSMasami Hiramatsu case EFAULT: 5577cf0b79eSMasami Hiramatsu raw_path = strchr(++raw_path, '/'); 5587cf0b79eSMasami Hiramatsu if (!raw_path) { 55904662523SArnaldo Carvalho de Melo zfree(new_path); 5607cf0b79eSMasami Hiramatsu return -ENOENT; 5617cf0b79eSMasami Hiramatsu } 5627cf0b79eSMasami Hiramatsu continue; 5637cf0b79eSMasami Hiramatsu 5647cf0b79eSMasami Hiramatsu default: 56504662523SArnaldo Carvalho de Melo zfree(new_path); 5667cf0b79eSMasami Hiramatsu return -errno; 5677cf0b79eSMasami Hiramatsu } 5687cf0b79eSMasami Hiramatsu } 5697cf0b79eSMasami Hiramatsu } 5707cf0b79eSMasami Hiramatsu 5714b4da7f7SMasami Hiramatsu #define LINEBUF_SIZE 256 5724b4da7f7SMasami Hiramatsu #define NR_ADDITIONAL_LINES 2 5734b4da7f7SMasami Hiramatsu 574fde52dbdSFranck Bui-Huu static int __show_one_line(FILE *fp, int l, bool skip, bool show_num) 5754b4da7f7SMasami Hiramatsu { 5765f03cba4SMasami Hiramatsu char buf[LINEBUF_SIZE], sbuf[STRERR_BUFSIZE]; 577befe3414SFranck Bui-Huu const char *color = show_num ? "" : PERF_COLOR_BLUE; 578befe3414SFranck Bui-Huu const char *prefix = NULL; 5794b4da7f7SMasami Hiramatsu 580befe3414SFranck Bui-Huu do { 5814b4da7f7SMasami Hiramatsu if (fgets(buf, LINEBUF_SIZE, fp) == NULL) 5824b4da7f7SMasami Hiramatsu goto error; 583befe3414SFranck Bui-Huu if (skip) 584befe3414SFranck Bui-Huu continue; 585befe3414SFranck Bui-Huu if (!prefix) { 586befe3414SFranck Bui-Huu prefix = show_num ? "%7d " : " "; 587befe3414SFranck Bui-Huu color_fprintf(stdout, color, prefix, l); 5884b4da7f7SMasami Hiramatsu } 589befe3414SFranck Bui-Huu color_fprintf(stdout, color, "%s", buf); 5904b4da7f7SMasami Hiramatsu 591befe3414SFranck Bui-Huu } while (strchr(buf, '\n') == NULL); 592146a1439SMasami Hiramatsu 593fde52dbdSFranck Bui-Huu return 1; 5944b4da7f7SMasami Hiramatsu error: 595fde52dbdSFranck Bui-Huu if (ferror(fp)) { 5965f03cba4SMasami Hiramatsu pr_warning("File read error: %s\n", 5975f03cba4SMasami Hiramatsu strerror_r(errno, sbuf, sizeof(sbuf))); 598146a1439SMasami Hiramatsu return -1; 5994b4da7f7SMasami Hiramatsu } 600fde52dbdSFranck Bui-Huu return 0; 601fde52dbdSFranck Bui-Huu } 602fde52dbdSFranck Bui-Huu 603fde52dbdSFranck Bui-Huu static int _show_one_line(FILE *fp, int l, bool skip, bool show_num) 604fde52dbdSFranck Bui-Huu { 605fde52dbdSFranck Bui-Huu int rv = __show_one_line(fp, l, skip, show_num); 606fde52dbdSFranck Bui-Huu if (rv == 0) { 607fde52dbdSFranck Bui-Huu pr_warning("Source file is shorter than expected.\n"); 608fde52dbdSFranck Bui-Huu rv = -1; 609fde52dbdSFranck Bui-Huu } 610fde52dbdSFranck Bui-Huu return rv; 611fde52dbdSFranck Bui-Huu } 612fde52dbdSFranck Bui-Huu 613fde52dbdSFranck Bui-Huu #define show_one_line_with_num(f,l) _show_one_line(f,l,false,true) 614fde52dbdSFranck Bui-Huu #define show_one_line(f,l) _show_one_line(f,l,false,false) 615fde52dbdSFranck Bui-Huu #define skip_one_line(f,l) _show_one_line(f,l,true,false) 616fde52dbdSFranck Bui-Huu #define show_one_line_or_eof(f,l) __show_one_line(f,l,false,false) 6174b4da7f7SMasami Hiramatsu 6184b4da7f7SMasami Hiramatsu /* 6194b4da7f7SMasami Hiramatsu * Show line-range always requires debuginfo to find source file and 6204b4da7f7SMasami Hiramatsu * line number. 6214b4da7f7SMasami Hiramatsu */ 622ee45b6c2SMasami Hiramatsu static int __show_line_range(struct line_range *lr, const char *module) 6234b4da7f7SMasami Hiramatsu { 624d3b63d7aSMasami Hiramatsu int l = 1; 6255a62257aSMasami Hiramatsu struct int_node *ln; 626ff741783SMasami Hiramatsu struct debuginfo *dinfo; 6274b4da7f7SMasami Hiramatsu FILE *fp; 628ff741783SMasami Hiramatsu int ret; 6297cf0b79eSMasami Hiramatsu char *tmp; 6305f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 6314b4da7f7SMasami Hiramatsu 6324b4da7f7SMasami Hiramatsu /* Search a line range */ 63392561cb7SMasami Hiramatsu dinfo = open_debuginfo(module, false); 63492561cb7SMasami Hiramatsu if (!dinfo) 635ff741783SMasami Hiramatsu return -ENOENT; 636146a1439SMasami Hiramatsu 637ff741783SMasami Hiramatsu ret = debuginfo__find_line_range(dinfo, lr); 638ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 6395ee05b88SMasami Hiramatsu if (ret == 0 || ret == -ENOENT) { 640146a1439SMasami Hiramatsu pr_warning("Specified source line is not found.\n"); 641146a1439SMasami Hiramatsu return -ENOENT; 642146a1439SMasami Hiramatsu } else if (ret < 0) { 6435ee05b88SMasami Hiramatsu pr_warning("Debuginfo analysis failed.\n"); 644146a1439SMasami Hiramatsu return ret; 645146a1439SMasami Hiramatsu } 6464b4da7f7SMasami Hiramatsu 6477cf0b79eSMasami Hiramatsu /* Convert source file path */ 6487cf0b79eSMasami Hiramatsu tmp = lr->path; 6496a330a3cSMasami Hiramatsu ret = get_real_path(tmp, lr->comp_dir, &lr->path); 6507cf0b79eSMasami Hiramatsu free(tmp); /* Free old path */ 6517cf0b79eSMasami Hiramatsu if (ret < 0) { 6525ee05b88SMasami Hiramatsu pr_warning("Failed to find source file path.\n"); 6537cf0b79eSMasami Hiramatsu return ret; 6547cf0b79eSMasami Hiramatsu } 6557cf0b79eSMasami Hiramatsu 6564b4da7f7SMasami Hiramatsu setup_pager(); 6574b4da7f7SMasami Hiramatsu 6584b4da7f7SMasami Hiramatsu if (lr->function) 6598737ebdeSMasami Hiramatsu fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path, 6604b4da7f7SMasami Hiramatsu lr->start - lr->offset); 6614b4da7f7SMasami Hiramatsu else 66262c15fc4SFranck Bui-Huu fprintf(stdout, "<%s:%d>\n", lr->path, lr->start); 6634b4da7f7SMasami Hiramatsu 6644b4da7f7SMasami Hiramatsu fp = fopen(lr->path, "r"); 665146a1439SMasami Hiramatsu if (fp == NULL) { 666146a1439SMasami Hiramatsu pr_warning("Failed to open %s: %s\n", lr->path, 6675f03cba4SMasami Hiramatsu strerror_r(errno, sbuf, sizeof(sbuf))); 668146a1439SMasami Hiramatsu return -errno; 669146a1439SMasami Hiramatsu } 6704b4da7f7SMasami Hiramatsu /* Skip to starting line number */ 67144b81e92SFranck Bui-Huu while (l < lr->start) { 672fde52dbdSFranck Bui-Huu ret = skip_one_line(fp, l++); 673146a1439SMasami Hiramatsu if (ret < 0) 674146a1439SMasami Hiramatsu goto end; 67544b81e92SFranck Bui-Huu } 6764b4da7f7SMasami Hiramatsu 6775a62257aSMasami Hiramatsu intlist__for_each(ln, lr->line_list) { 6785a62257aSMasami Hiramatsu for (; ln->i > l; l++) { 679fde52dbdSFranck Bui-Huu ret = show_one_line(fp, l - lr->offset); 68044b81e92SFranck Bui-Huu if (ret < 0) 68144b81e92SFranck Bui-Huu goto end; 68244b81e92SFranck Bui-Huu } 683fde52dbdSFranck Bui-Huu ret = show_one_line_with_num(fp, l++ - lr->offset); 684146a1439SMasami Hiramatsu if (ret < 0) 685146a1439SMasami Hiramatsu goto end; 6864b4da7f7SMasami Hiramatsu } 6874b4da7f7SMasami Hiramatsu 6884b4da7f7SMasami Hiramatsu if (lr->end == INT_MAX) 6894b4da7f7SMasami Hiramatsu lr->end = l + NR_ADDITIONAL_LINES; 690fde52dbdSFranck Bui-Huu while (l <= lr->end) { 691fde52dbdSFranck Bui-Huu ret = show_one_line_or_eof(fp, l++ - lr->offset); 692fde52dbdSFranck Bui-Huu if (ret <= 0) 69344b81e92SFranck Bui-Huu break; 69444b81e92SFranck Bui-Huu } 695146a1439SMasami Hiramatsu end: 6964b4da7f7SMasami Hiramatsu fclose(fp); 697146a1439SMasami Hiramatsu return ret; 6984b4da7f7SMasami Hiramatsu } 6994b4da7f7SMasami Hiramatsu 700*2b394bc4SMasami Hiramatsu int show_line_range(struct line_range *lr, const char *module, bool user) 701ee45b6c2SMasami Hiramatsu { 702ee45b6c2SMasami Hiramatsu int ret; 703ee45b6c2SMasami Hiramatsu 704*2b394bc4SMasami Hiramatsu ret = init_symbol_maps(user); 705ee45b6c2SMasami Hiramatsu if (ret < 0) 706ee45b6c2SMasami Hiramatsu return ret; 707ee45b6c2SMasami Hiramatsu ret = __show_line_range(lr, module); 708ee45b6c2SMasami Hiramatsu exit_symbol_maps(); 709ee45b6c2SMasami Hiramatsu 710ee45b6c2SMasami Hiramatsu return ret; 711ee45b6c2SMasami Hiramatsu } 712ee45b6c2SMasami Hiramatsu 713ff741783SMasami Hiramatsu static int show_available_vars_at(struct debuginfo *dinfo, 714ff741783SMasami Hiramatsu struct perf_probe_event *pev, 715bd09d7b5SMasami Hiramatsu int max_vls, struct strfilter *_filter, 716bd09d7b5SMasami Hiramatsu bool externs) 717cf6eb489SMasami Hiramatsu { 718cf6eb489SMasami Hiramatsu char *buf; 719bd09d7b5SMasami Hiramatsu int ret, i, nvars; 720cf6eb489SMasami Hiramatsu struct str_node *node; 721cf6eb489SMasami Hiramatsu struct variable_list *vls = NULL, *vl; 722bd09d7b5SMasami Hiramatsu const char *var; 723cf6eb489SMasami Hiramatsu 724cf6eb489SMasami Hiramatsu buf = synthesize_perf_probe_point(&pev->point); 725cf6eb489SMasami Hiramatsu if (!buf) 726cf6eb489SMasami Hiramatsu return -EINVAL; 727cf6eb489SMasami Hiramatsu pr_debug("Searching variables at %s\n", buf); 728cf6eb489SMasami Hiramatsu 729ff741783SMasami Hiramatsu ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, 730ff741783SMasami Hiramatsu max_vls, externs); 731bd09d7b5SMasami Hiramatsu if (ret <= 0) { 73269e96eaaSMasami Hiramatsu if (ret == 0 || ret == -ENOENT) { 73369e96eaaSMasami Hiramatsu pr_err("Failed to find the address of %s\n", buf); 73469e96eaaSMasami Hiramatsu ret = -ENOENT; 73569e96eaaSMasami Hiramatsu } else 73669e96eaaSMasami Hiramatsu pr_warning("Debuginfo analysis failed.\n"); 737bd09d7b5SMasami Hiramatsu goto end; 738bd09d7b5SMasami Hiramatsu } 73969e96eaaSMasami Hiramatsu 740bd09d7b5SMasami Hiramatsu /* Some variables are found */ 741cf6eb489SMasami Hiramatsu fprintf(stdout, "Available variables at %s\n", buf); 742cf6eb489SMasami Hiramatsu for (i = 0; i < ret; i++) { 743cf6eb489SMasami Hiramatsu vl = &vls[i]; 744cf6eb489SMasami Hiramatsu /* 745cf6eb489SMasami Hiramatsu * A probe point might be converted to 746cf6eb489SMasami Hiramatsu * several trace points. 747cf6eb489SMasami Hiramatsu */ 748cf6eb489SMasami Hiramatsu fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, 749cf6eb489SMasami Hiramatsu vl->point.offset); 75074cf249dSArnaldo Carvalho de Melo zfree(&vl->point.symbol); 751bd09d7b5SMasami Hiramatsu nvars = 0; 752cf6eb489SMasami Hiramatsu if (vl->vars) { 753bd09d7b5SMasami Hiramatsu strlist__for_each(node, vl->vars) { 754bd09d7b5SMasami Hiramatsu var = strchr(node->s, '\t') + 1; 755bd09d7b5SMasami Hiramatsu if (strfilter__compare(_filter, var)) { 756cf6eb489SMasami Hiramatsu fprintf(stdout, "\t\t%s\n", node->s); 757bd09d7b5SMasami Hiramatsu nvars++; 758bd09d7b5SMasami Hiramatsu } 759bd09d7b5SMasami Hiramatsu } 760cf6eb489SMasami Hiramatsu strlist__delete(vl->vars); 761bd09d7b5SMasami Hiramatsu } 762bd09d7b5SMasami Hiramatsu if (nvars == 0) 763bd09d7b5SMasami Hiramatsu fprintf(stdout, "\t\t(No matched variables)\n"); 764cf6eb489SMasami Hiramatsu } 765cf6eb489SMasami Hiramatsu free(vls); 766bd09d7b5SMasami Hiramatsu end: 767cf6eb489SMasami Hiramatsu free(buf); 768cf6eb489SMasami Hiramatsu return ret; 769cf6eb489SMasami Hiramatsu } 770cf6eb489SMasami Hiramatsu 771cf6eb489SMasami Hiramatsu /* Show available variables on given probe point */ 772cf6eb489SMasami Hiramatsu int show_available_vars(struct perf_probe_event *pevs, int npevs, 773bd09d7b5SMasami Hiramatsu int max_vls, const char *module, 774bd09d7b5SMasami Hiramatsu struct strfilter *_filter, bool externs) 775cf6eb489SMasami Hiramatsu { 776ff741783SMasami Hiramatsu int i, ret = 0; 777ff741783SMasami Hiramatsu struct debuginfo *dinfo; 778cf6eb489SMasami Hiramatsu 779*2b394bc4SMasami Hiramatsu ret = init_symbol_maps(pevs->uprobes); 780cf6eb489SMasami Hiramatsu if (ret < 0) 781cf6eb489SMasami Hiramatsu return ret; 782cf6eb489SMasami Hiramatsu 78392561cb7SMasami Hiramatsu dinfo = open_debuginfo(module, false); 784ff741783SMasami Hiramatsu if (!dinfo) { 785ee45b6c2SMasami Hiramatsu ret = -ENOENT; 786ee45b6c2SMasami Hiramatsu goto out; 787ff741783SMasami Hiramatsu } 788ff741783SMasami Hiramatsu 789cc446446SMasami Hiramatsu setup_pager(); 790cc446446SMasami Hiramatsu 791ff741783SMasami Hiramatsu for (i = 0; i < npevs && ret >= 0; i++) 792ff741783SMasami Hiramatsu ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter, 793bd09d7b5SMasami Hiramatsu externs); 794ff741783SMasami Hiramatsu 795ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 796ee45b6c2SMasami Hiramatsu out: 797ee45b6c2SMasami Hiramatsu exit_symbol_maps(); 798cf6eb489SMasami Hiramatsu return ret; 799cf6eb489SMasami Hiramatsu } 800cf6eb489SMasami Hiramatsu 80189fe808aSIngo Molnar #else /* !HAVE_DWARF_SUPPORT */ 8024b4da7f7SMasami Hiramatsu 8035a6f6314SMasami Hiramatsu static int 8045a6f6314SMasami Hiramatsu find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused, 8055a6f6314SMasami Hiramatsu struct perf_probe_point *pp __maybe_unused, 8065a6f6314SMasami Hiramatsu bool is_kprobe __maybe_unused) 8074b4da7f7SMasami Hiramatsu { 8085a6f6314SMasami Hiramatsu return -ENOSYS; 8094b4da7f7SMasami Hiramatsu } 8104b4da7f7SMasami Hiramatsu 8110e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 8121d037ca1SIrina Tirdea struct probe_trace_event **tevs __maybe_unused, 8131d027ee9SArnaldo Carvalho de Melo int max_tevs __maybe_unused, 8141d027ee9SArnaldo Carvalho de Melo const char *target __maybe_unused) 8154b4da7f7SMasami Hiramatsu { 816146a1439SMasami Hiramatsu if (perf_probe_event_need_dwarf(pev)) { 817146a1439SMasami Hiramatsu pr_warning("Debuginfo-analysis is not supported.\n"); 818146a1439SMasami Hiramatsu return -ENOSYS; 819146a1439SMasami Hiramatsu } 820225466f1SSrikar Dronamraju 8214b4da7f7SMasami Hiramatsu return 0; 8224b4da7f7SMasami Hiramatsu } 8234b4da7f7SMasami Hiramatsu 8241d037ca1SIrina Tirdea int show_line_range(struct line_range *lr __maybe_unused, 825*2b394bc4SMasami Hiramatsu const char *module __maybe_unused, 826*2b394bc4SMasami Hiramatsu bool user __maybe_unused) 8274b4da7f7SMasami Hiramatsu { 828146a1439SMasami Hiramatsu pr_warning("Debuginfo-analysis is not supported.\n"); 829146a1439SMasami Hiramatsu return -ENOSYS; 8304b4da7f7SMasami Hiramatsu } 8314b4da7f7SMasami Hiramatsu 8321d037ca1SIrina Tirdea int show_available_vars(struct perf_probe_event *pevs __maybe_unused, 8331d037ca1SIrina Tirdea int npevs __maybe_unused, int max_vls __maybe_unused, 8341d037ca1SIrina Tirdea const char *module __maybe_unused, 8351d037ca1SIrina Tirdea struct strfilter *filter __maybe_unused, 8361d037ca1SIrina Tirdea bool externs __maybe_unused) 837cf6eb489SMasami Hiramatsu { 838cf6eb489SMasami Hiramatsu pr_warning("Debuginfo-analysis is not supported.\n"); 839cf6eb489SMasami Hiramatsu return -ENOSYS; 840cf6eb489SMasami Hiramatsu } 841e0faa8d3SMasami Hiramatsu #endif 842e0faa8d3SMasami Hiramatsu 843e53b00d3SMasami Hiramatsu void line_range__clear(struct line_range *lr) 844e53b00d3SMasami Hiramatsu { 845e53b00d3SMasami Hiramatsu free(lr->function); 846e53b00d3SMasami Hiramatsu free(lr->file); 847e53b00d3SMasami Hiramatsu free(lr->path); 848e53b00d3SMasami Hiramatsu free(lr->comp_dir); 8495a62257aSMasami Hiramatsu intlist__delete(lr->line_list); 850e53b00d3SMasami Hiramatsu memset(lr, 0, sizeof(*lr)); 851e53b00d3SMasami Hiramatsu } 852e53b00d3SMasami Hiramatsu 8535a62257aSMasami Hiramatsu int line_range__init(struct line_range *lr) 854e53b00d3SMasami Hiramatsu { 855e53b00d3SMasami Hiramatsu memset(lr, 0, sizeof(*lr)); 8565a62257aSMasami Hiramatsu lr->line_list = intlist__new(NULL); 8575a62257aSMasami Hiramatsu if (!lr->line_list) 8585a62257aSMasami Hiramatsu return -ENOMEM; 8595a62257aSMasami Hiramatsu else 8605a62257aSMasami Hiramatsu return 0; 861e53b00d3SMasami Hiramatsu } 862e53b00d3SMasami Hiramatsu 86321dd9ae5SFranck Bui-Huu static int parse_line_num(char **ptr, int *val, const char *what) 86421dd9ae5SFranck Bui-Huu { 86521dd9ae5SFranck Bui-Huu const char *start = *ptr; 86621dd9ae5SFranck Bui-Huu 86721dd9ae5SFranck Bui-Huu errno = 0; 86821dd9ae5SFranck Bui-Huu *val = strtol(*ptr, ptr, 0); 86921dd9ae5SFranck Bui-Huu if (errno || *ptr == start) { 87021dd9ae5SFranck Bui-Huu semantic_error("'%s' is not a valid number.\n", what); 87121dd9ae5SFranck Bui-Huu return -EINVAL; 87221dd9ae5SFranck Bui-Huu } 87321dd9ae5SFranck Bui-Huu return 0; 87421dd9ae5SFranck Bui-Huu } 87521dd9ae5SFranck Bui-Huu 8769d95b580SFranck Bui-Huu /* 8779d95b580SFranck Bui-Huu * Stuff 'lr' according to the line range described by 'arg'. 8789d95b580SFranck Bui-Huu * The line range syntax is described by: 8799d95b580SFranck Bui-Huu * 8809d95b580SFranck Bui-Huu * SRC[:SLN[+NUM|-ELN]] 881e116dfa1SMasami Hiramatsu * FNC[@SRC][:SLN[+NUM|-ELN]] 8829d95b580SFranck Bui-Huu */ 883146a1439SMasami Hiramatsu int parse_line_range_desc(const char *arg, struct line_range *lr) 884631c9defSMasami Hiramatsu { 885e116dfa1SMasami Hiramatsu char *range, *file, *name = strdup(arg); 88621dd9ae5SFranck Bui-Huu int err; 8879d95b580SFranck Bui-Huu 88821dd9ae5SFranck Bui-Huu if (!name) 88921dd9ae5SFranck Bui-Huu return -ENOMEM; 89021dd9ae5SFranck Bui-Huu 89121dd9ae5SFranck Bui-Huu lr->start = 0; 89221dd9ae5SFranck Bui-Huu lr->end = INT_MAX; 89321dd9ae5SFranck Bui-Huu 89421dd9ae5SFranck Bui-Huu range = strchr(name, ':'); 89521dd9ae5SFranck Bui-Huu if (range) { 89621dd9ae5SFranck Bui-Huu *range++ = '\0'; 89721dd9ae5SFranck Bui-Huu 89821dd9ae5SFranck Bui-Huu err = parse_line_num(&range, &lr->start, "start line"); 89921dd9ae5SFranck Bui-Huu if (err) 90021dd9ae5SFranck Bui-Huu goto err; 90121dd9ae5SFranck Bui-Huu 90221dd9ae5SFranck Bui-Huu if (*range == '+' || *range == '-') { 90321dd9ae5SFranck Bui-Huu const char c = *range++; 90421dd9ae5SFranck Bui-Huu 90521dd9ae5SFranck Bui-Huu err = parse_line_num(&range, &lr->end, "end line"); 90621dd9ae5SFranck Bui-Huu if (err) 90721dd9ae5SFranck Bui-Huu goto err; 90821dd9ae5SFranck Bui-Huu 90921dd9ae5SFranck Bui-Huu if (c == '+') { 91021dd9ae5SFranck Bui-Huu lr->end += lr->start; 91121dd9ae5SFranck Bui-Huu /* 912dda4ab34SMasami Hiramatsu * Adjust the number of lines here. 913dda4ab34SMasami Hiramatsu * If the number of lines == 1, the 914dda4ab34SMasami Hiramatsu * the end of line should be equal to 915dda4ab34SMasami Hiramatsu * the start of line. 916dda4ab34SMasami Hiramatsu */ 91721dd9ae5SFranck Bui-Huu lr->end--; 91821dd9ae5SFranck Bui-Huu } 91921dd9ae5SFranck Bui-Huu } 92021dd9ae5SFranck Bui-Huu 921d3b63d7aSMasami Hiramatsu pr_debug("Line range is %d to %d\n", lr->start, lr->end); 92221dd9ae5SFranck Bui-Huu 92321dd9ae5SFranck Bui-Huu err = -EINVAL; 924d3b63d7aSMasami Hiramatsu if (lr->start > lr->end) { 925631c9defSMasami Hiramatsu semantic_error("Start line must be smaller" 926146a1439SMasami Hiramatsu " than end line.\n"); 92721dd9ae5SFranck Bui-Huu goto err; 928146a1439SMasami Hiramatsu } 92921dd9ae5SFranck Bui-Huu if (*range != '\0') { 93021dd9ae5SFranck Bui-Huu semantic_error("Tailing with invalid str '%s'.\n", range); 93121dd9ae5SFranck Bui-Huu goto err; 932146a1439SMasami Hiramatsu } 933d3b63d7aSMasami Hiramatsu } 93402b95dadSMasami Hiramatsu 935e116dfa1SMasami Hiramatsu file = strchr(name, '@'); 936e116dfa1SMasami Hiramatsu if (file) { 937e116dfa1SMasami Hiramatsu *file = '\0'; 938e116dfa1SMasami Hiramatsu lr->file = strdup(++file); 939e116dfa1SMasami Hiramatsu if (lr->file == NULL) { 940e116dfa1SMasami Hiramatsu err = -ENOMEM; 941e116dfa1SMasami Hiramatsu goto err; 942e116dfa1SMasami Hiramatsu } 943e116dfa1SMasami Hiramatsu lr->function = name; 944e116dfa1SMasami Hiramatsu } else if (strchr(name, '.')) 94521dd9ae5SFranck Bui-Huu lr->file = name; 946631c9defSMasami Hiramatsu else 94721dd9ae5SFranck Bui-Huu lr->function = name; 948146a1439SMasami Hiramatsu 949146a1439SMasami Hiramatsu return 0; 95021dd9ae5SFranck Bui-Huu err: 95121dd9ae5SFranck Bui-Huu free(name); 95221dd9ae5SFranck Bui-Huu return err; 953631c9defSMasami Hiramatsu } 954631c9defSMasami Hiramatsu 955b7702a21SMasami Hiramatsu /* Check the name is good for event/group */ 956b7702a21SMasami Hiramatsu static bool check_event_name(const char *name) 957b7702a21SMasami Hiramatsu { 958b7702a21SMasami Hiramatsu if (!isalpha(*name) && *name != '_') 959b7702a21SMasami Hiramatsu return false; 960b7702a21SMasami Hiramatsu while (*++name != '\0') { 961b7702a21SMasami Hiramatsu if (!isalpha(*name) && !isdigit(*name) && *name != '_') 962b7702a21SMasami Hiramatsu return false; 963b7702a21SMasami Hiramatsu } 964b7702a21SMasami Hiramatsu return true; 965b7702a21SMasami Hiramatsu } 966b7702a21SMasami Hiramatsu 96750656eecSMasami Hiramatsu /* Parse probepoint definition. */ 968146a1439SMasami Hiramatsu static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) 96950656eecSMasami Hiramatsu { 9704235b045SMasami Hiramatsu struct perf_probe_point *pp = &pev->point; 97150656eecSMasami Hiramatsu char *ptr, *tmp; 97250656eecSMasami Hiramatsu char c, nc = 0; 97350656eecSMasami Hiramatsu /* 97450656eecSMasami Hiramatsu * <Syntax> 9752a9c8c36SMasami Hiramatsu * perf probe [EVENT=]SRC[:LN|;PTN] 9762a9c8c36SMasami Hiramatsu * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] 977af663d75SMasami Hiramatsu * 978af663d75SMasami Hiramatsu * TODO:Group name support 97950656eecSMasami Hiramatsu */ 98050656eecSMasami Hiramatsu 9812a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";=@+%"); 9822a9c8c36SMasami Hiramatsu if (ptr && *ptr == '=') { /* Event name */ 983af663d75SMasami Hiramatsu *ptr = '\0'; 984af663d75SMasami Hiramatsu tmp = ptr + 1; 985146a1439SMasami Hiramatsu if (strchr(arg, ':')) { 986146a1439SMasami Hiramatsu semantic_error("Group name is not supported yet.\n"); 987146a1439SMasami Hiramatsu return -ENOTSUP; 988146a1439SMasami Hiramatsu } 989146a1439SMasami Hiramatsu if (!check_event_name(arg)) { 990b7702a21SMasami Hiramatsu semantic_error("%s is bad for event name -it must " 991146a1439SMasami Hiramatsu "follow C symbol-naming rule.\n", arg); 992146a1439SMasami Hiramatsu return -EINVAL; 993146a1439SMasami Hiramatsu } 99402b95dadSMasami Hiramatsu pev->event = strdup(arg); 99502b95dadSMasami Hiramatsu if (pev->event == NULL) 99602b95dadSMasami Hiramatsu return -ENOMEM; 9974235b045SMasami Hiramatsu pev->group = NULL; 998af663d75SMasami Hiramatsu arg = tmp; 999af663d75SMasami Hiramatsu } 1000af663d75SMasami Hiramatsu 10012a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";:+@%"); 100250656eecSMasami Hiramatsu if (ptr) { 100350656eecSMasami Hiramatsu nc = *ptr; 100450656eecSMasami Hiramatsu *ptr++ = '\0'; 100550656eecSMasami Hiramatsu } 100650656eecSMasami Hiramatsu 100702b95dadSMasami Hiramatsu tmp = strdup(arg); 100802b95dadSMasami Hiramatsu if (tmp == NULL) 100902b95dadSMasami Hiramatsu return -ENOMEM; 101002b95dadSMasami Hiramatsu 101150656eecSMasami Hiramatsu /* Check arg is function or file and copy it */ 101202b95dadSMasami Hiramatsu if (strchr(tmp, '.')) /* File */ 101302b95dadSMasami Hiramatsu pp->file = tmp; 101450656eecSMasami Hiramatsu else /* Function */ 101502b95dadSMasami Hiramatsu pp->function = tmp; 101650656eecSMasami Hiramatsu 101750656eecSMasami Hiramatsu /* Parse other options */ 101850656eecSMasami Hiramatsu while (ptr) { 101950656eecSMasami Hiramatsu arg = ptr; 102050656eecSMasami Hiramatsu c = nc; 10212a9c8c36SMasami Hiramatsu if (c == ';') { /* Lazy pattern must be the last part */ 102202b95dadSMasami Hiramatsu pp->lazy_line = strdup(arg); 102302b95dadSMasami Hiramatsu if (pp->lazy_line == NULL) 102402b95dadSMasami Hiramatsu return -ENOMEM; 10252a9c8c36SMasami Hiramatsu break; 10262a9c8c36SMasami Hiramatsu } 10272a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";:+@%"); 102850656eecSMasami Hiramatsu if (ptr) { 102950656eecSMasami Hiramatsu nc = *ptr; 103050656eecSMasami Hiramatsu *ptr++ = '\0'; 103150656eecSMasami Hiramatsu } 103250656eecSMasami Hiramatsu switch (c) { 103350656eecSMasami Hiramatsu case ':': /* Line number */ 103450656eecSMasami Hiramatsu pp->line = strtoul(arg, &tmp, 0); 1035146a1439SMasami Hiramatsu if (*tmp != '\0') { 10362a9c8c36SMasami Hiramatsu semantic_error("There is non-digit char" 1037146a1439SMasami Hiramatsu " in line number.\n"); 1038146a1439SMasami Hiramatsu return -EINVAL; 1039146a1439SMasami Hiramatsu } 104050656eecSMasami Hiramatsu break; 104150656eecSMasami Hiramatsu case '+': /* Byte offset from a symbol */ 104250656eecSMasami Hiramatsu pp->offset = strtoul(arg, &tmp, 0); 1043146a1439SMasami Hiramatsu if (*tmp != '\0') { 10442a9c8c36SMasami Hiramatsu semantic_error("There is non-digit character" 1045146a1439SMasami Hiramatsu " in offset.\n"); 1046146a1439SMasami Hiramatsu return -EINVAL; 1047146a1439SMasami Hiramatsu } 104850656eecSMasami Hiramatsu break; 104950656eecSMasami Hiramatsu case '@': /* File name */ 1050146a1439SMasami Hiramatsu if (pp->file) { 1051146a1439SMasami Hiramatsu semantic_error("SRC@SRC is not allowed.\n"); 1052146a1439SMasami Hiramatsu return -EINVAL; 1053146a1439SMasami Hiramatsu } 105402b95dadSMasami Hiramatsu pp->file = strdup(arg); 105502b95dadSMasami Hiramatsu if (pp->file == NULL) 105602b95dadSMasami Hiramatsu return -ENOMEM; 105750656eecSMasami Hiramatsu break; 105850656eecSMasami Hiramatsu case '%': /* Probe places */ 105950656eecSMasami Hiramatsu if (strcmp(arg, "return") == 0) { 106050656eecSMasami Hiramatsu pp->retprobe = 1; 1061146a1439SMasami Hiramatsu } else { /* Others not supported yet */ 1062146a1439SMasami Hiramatsu semantic_error("%%%s is not supported.\n", arg); 1063146a1439SMasami Hiramatsu return -ENOTSUP; 1064146a1439SMasami Hiramatsu } 106550656eecSMasami Hiramatsu break; 1066146a1439SMasami Hiramatsu default: /* Buggy case */ 1067146a1439SMasami Hiramatsu pr_err("This program has a bug at %s:%d.\n", 1068146a1439SMasami Hiramatsu __FILE__, __LINE__); 1069146a1439SMasami Hiramatsu return -ENOTSUP; 107050656eecSMasami Hiramatsu break; 107150656eecSMasami Hiramatsu } 107250656eecSMasami Hiramatsu } 107350656eecSMasami Hiramatsu 107450656eecSMasami Hiramatsu /* Exclusion check */ 1075146a1439SMasami Hiramatsu if (pp->lazy_line && pp->line) { 10760e43e5d2SMasami Hiramatsu semantic_error("Lazy pattern can't be used with" 10770e43e5d2SMasami Hiramatsu " line number.\n"); 1078146a1439SMasami Hiramatsu return -EINVAL; 1079146a1439SMasami Hiramatsu } 10802a9c8c36SMasami Hiramatsu 1081146a1439SMasami Hiramatsu if (pp->lazy_line && pp->offset) { 10820e43e5d2SMasami Hiramatsu semantic_error("Lazy pattern can't be used with offset.\n"); 1083146a1439SMasami Hiramatsu return -EINVAL; 1084146a1439SMasami Hiramatsu } 10852a9c8c36SMasami Hiramatsu 1086146a1439SMasami Hiramatsu if (pp->line && pp->offset) { 10870e43e5d2SMasami Hiramatsu semantic_error("Offset can't be used with line number.\n"); 1088146a1439SMasami Hiramatsu return -EINVAL; 1089146a1439SMasami Hiramatsu } 109050656eecSMasami Hiramatsu 1091146a1439SMasami Hiramatsu if (!pp->line && !pp->lazy_line && pp->file && !pp->function) { 10922a9c8c36SMasami Hiramatsu semantic_error("File always requires line number or " 10930e43e5d2SMasami Hiramatsu "lazy pattern.\n"); 1094146a1439SMasami Hiramatsu return -EINVAL; 1095146a1439SMasami Hiramatsu } 109650656eecSMasami Hiramatsu 1097146a1439SMasami Hiramatsu if (pp->offset && !pp->function) { 10980e43e5d2SMasami Hiramatsu semantic_error("Offset requires an entry function.\n"); 1099146a1439SMasami Hiramatsu return -EINVAL; 1100146a1439SMasami Hiramatsu } 110150656eecSMasami Hiramatsu 1102146a1439SMasami Hiramatsu if (pp->retprobe && !pp->function) { 11030e43e5d2SMasami Hiramatsu semantic_error("Return probe requires an entry function.\n"); 1104146a1439SMasami Hiramatsu return -EINVAL; 1105146a1439SMasami Hiramatsu } 110650656eecSMasami Hiramatsu 1107146a1439SMasami Hiramatsu if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { 11082a9c8c36SMasami Hiramatsu semantic_error("Offset/Line/Lazy pattern can't be used with " 11090e43e5d2SMasami Hiramatsu "return probe.\n"); 1110146a1439SMasami Hiramatsu return -EINVAL; 1111146a1439SMasami Hiramatsu } 111250656eecSMasami Hiramatsu 11134235b045SMasami Hiramatsu pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n", 11142a9c8c36SMasami Hiramatsu pp->function, pp->file, pp->line, pp->offset, pp->retprobe, 11152a9c8c36SMasami Hiramatsu pp->lazy_line); 1116146a1439SMasami Hiramatsu return 0; 111750656eecSMasami Hiramatsu } 111850656eecSMasami Hiramatsu 11197df2f329SMasami Hiramatsu /* Parse perf-probe event argument */ 1120146a1439SMasami Hiramatsu static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) 11217df2f329SMasami Hiramatsu { 1122b2a3c12bSMasami Hiramatsu char *tmp, *goodname; 11237df2f329SMasami Hiramatsu struct perf_probe_arg_field **fieldp; 11247df2f329SMasami Hiramatsu 11257df2f329SMasami Hiramatsu pr_debug("parsing arg: %s into ", str); 11267df2f329SMasami Hiramatsu 112748481938SMasami Hiramatsu tmp = strchr(str, '='); 112848481938SMasami Hiramatsu if (tmp) { 112902b95dadSMasami Hiramatsu arg->name = strndup(str, tmp - str); 113002b95dadSMasami Hiramatsu if (arg->name == NULL) 113102b95dadSMasami Hiramatsu return -ENOMEM; 113211a1ca35SMasami Hiramatsu pr_debug("name:%s ", arg->name); 113348481938SMasami Hiramatsu str = tmp + 1; 113448481938SMasami Hiramatsu } 113548481938SMasami Hiramatsu 113611a1ca35SMasami Hiramatsu tmp = strchr(str, ':'); 113711a1ca35SMasami Hiramatsu if (tmp) { /* Type setting */ 113811a1ca35SMasami Hiramatsu *tmp = '\0'; 113902b95dadSMasami Hiramatsu arg->type = strdup(tmp + 1); 114002b95dadSMasami Hiramatsu if (arg->type == NULL) 114102b95dadSMasami Hiramatsu return -ENOMEM; 114211a1ca35SMasami Hiramatsu pr_debug("type:%s ", arg->type); 114311a1ca35SMasami Hiramatsu } 114411a1ca35SMasami Hiramatsu 1145b2a3c12bSMasami Hiramatsu tmp = strpbrk(str, "-.["); 11467df2f329SMasami Hiramatsu if (!is_c_varname(str) || !tmp) { 11477df2f329SMasami Hiramatsu /* A variable, register, symbol or special value */ 114802b95dadSMasami Hiramatsu arg->var = strdup(str); 114902b95dadSMasami Hiramatsu if (arg->var == NULL) 115002b95dadSMasami Hiramatsu return -ENOMEM; 115148481938SMasami Hiramatsu pr_debug("%s\n", arg->var); 1152146a1439SMasami Hiramatsu return 0; 11537df2f329SMasami Hiramatsu } 11547df2f329SMasami Hiramatsu 1155b2a3c12bSMasami Hiramatsu /* Structure fields or array element */ 115602b95dadSMasami Hiramatsu arg->var = strndup(str, tmp - str); 115702b95dadSMasami Hiramatsu if (arg->var == NULL) 115802b95dadSMasami Hiramatsu return -ENOMEM; 1159b2a3c12bSMasami Hiramatsu goodname = arg->var; 116048481938SMasami Hiramatsu pr_debug("%s, ", arg->var); 11617df2f329SMasami Hiramatsu fieldp = &arg->field; 11627df2f329SMasami Hiramatsu 11637df2f329SMasami Hiramatsu do { 1164e334016fSMasami Hiramatsu *fieldp = zalloc(sizeof(struct perf_probe_arg_field)); 1165e334016fSMasami Hiramatsu if (*fieldp == NULL) 1166e334016fSMasami Hiramatsu return -ENOMEM; 1167b2a3c12bSMasami Hiramatsu if (*tmp == '[') { /* Array */ 1168b2a3c12bSMasami Hiramatsu str = tmp; 1169b2a3c12bSMasami Hiramatsu (*fieldp)->index = strtol(str + 1, &tmp, 0); 1170b2a3c12bSMasami Hiramatsu (*fieldp)->ref = true; 1171b2a3c12bSMasami Hiramatsu if (*tmp != ']' || tmp == str + 1) { 1172b2a3c12bSMasami Hiramatsu semantic_error("Array index must be a" 1173b2a3c12bSMasami Hiramatsu " number.\n"); 1174b2a3c12bSMasami Hiramatsu return -EINVAL; 1175b2a3c12bSMasami Hiramatsu } 1176b2a3c12bSMasami Hiramatsu tmp++; 1177b2a3c12bSMasami Hiramatsu if (*tmp == '\0') 1178b2a3c12bSMasami Hiramatsu tmp = NULL; 1179b2a3c12bSMasami Hiramatsu } else { /* Structure */ 11807df2f329SMasami Hiramatsu if (*tmp == '.') { 11817df2f329SMasami Hiramatsu str = tmp + 1; 11827df2f329SMasami Hiramatsu (*fieldp)->ref = false; 11837df2f329SMasami Hiramatsu } else if (tmp[1] == '>') { 11847df2f329SMasami Hiramatsu str = tmp + 2; 11857df2f329SMasami Hiramatsu (*fieldp)->ref = true; 1186146a1439SMasami Hiramatsu } else { 1187b2a3c12bSMasami Hiramatsu semantic_error("Argument parse error: %s\n", 1188b2a3c12bSMasami Hiramatsu str); 1189146a1439SMasami Hiramatsu return -EINVAL; 1190146a1439SMasami Hiramatsu } 1191b2a3c12bSMasami Hiramatsu tmp = strpbrk(str, "-.["); 1192b2a3c12bSMasami Hiramatsu } 11937df2f329SMasami Hiramatsu if (tmp) { 119402b95dadSMasami Hiramatsu (*fieldp)->name = strndup(str, tmp - str); 119502b95dadSMasami Hiramatsu if ((*fieldp)->name == NULL) 119602b95dadSMasami Hiramatsu return -ENOMEM; 1197b2a3c12bSMasami Hiramatsu if (*str != '[') 1198b2a3c12bSMasami Hiramatsu goodname = (*fieldp)->name; 11997df2f329SMasami Hiramatsu pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); 12007df2f329SMasami Hiramatsu fieldp = &(*fieldp)->next; 12017df2f329SMasami Hiramatsu } 12027df2f329SMasami Hiramatsu } while (tmp); 120302b95dadSMasami Hiramatsu (*fieldp)->name = strdup(str); 120402b95dadSMasami Hiramatsu if ((*fieldp)->name == NULL) 120502b95dadSMasami Hiramatsu return -ENOMEM; 1206b2a3c12bSMasami Hiramatsu if (*str != '[') 1207b2a3c12bSMasami Hiramatsu goodname = (*fieldp)->name; 12087df2f329SMasami Hiramatsu pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); 1209df0faf4bSMasami Hiramatsu 1210b2a3c12bSMasami Hiramatsu /* If no name is specified, set the last field name (not array index)*/ 121102b95dadSMasami Hiramatsu if (!arg->name) { 1212b2a3c12bSMasami Hiramatsu arg->name = strdup(goodname); 121302b95dadSMasami Hiramatsu if (arg->name == NULL) 121402b95dadSMasami Hiramatsu return -ENOMEM; 121502b95dadSMasami Hiramatsu } 1216146a1439SMasami Hiramatsu return 0; 12177df2f329SMasami Hiramatsu } 12187df2f329SMasami Hiramatsu 12194235b045SMasami Hiramatsu /* Parse perf-probe event command */ 1220146a1439SMasami Hiramatsu int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) 122150656eecSMasami Hiramatsu { 1222e1c01d61SMasami Hiramatsu char **argv; 1223146a1439SMasami Hiramatsu int argc, i, ret = 0; 1224fac13fd5SMasami Hiramatsu 12254235b045SMasami Hiramatsu argv = argv_split(cmd, &argc); 1226146a1439SMasami Hiramatsu if (!argv) { 1227146a1439SMasami Hiramatsu pr_debug("Failed to split arguments.\n"); 1228146a1439SMasami Hiramatsu return -ENOMEM; 1229146a1439SMasami Hiramatsu } 1230146a1439SMasami Hiramatsu if (argc - 1 > MAX_PROBE_ARGS) { 1231146a1439SMasami Hiramatsu semantic_error("Too many probe arguments (%d).\n", argc - 1); 1232146a1439SMasami Hiramatsu ret = -ERANGE; 1233146a1439SMasami Hiramatsu goto out; 1234146a1439SMasami Hiramatsu } 123550656eecSMasami Hiramatsu /* Parse probe point */ 1236146a1439SMasami Hiramatsu ret = parse_perf_probe_point(argv[0], pev); 1237146a1439SMasami Hiramatsu if (ret < 0) 1238146a1439SMasami Hiramatsu goto out; 123950656eecSMasami Hiramatsu 1240e1c01d61SMasami Hiramatsu /* Copy arguments and ensure return probe has no C argument */ 12414235b045SMasami Hiramatsu pev->nargs = argc - 1; 1242e334016fSMasami Hiramatsu pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); 1243e334016fSMasami Hiramatsu if (pev->args == NULL) { 1244e334016fSMasami Hiramatsu ret = -ENOMEM; 1245e334016fSMasami Hiramatsu goto out; 1246e334016fSMasami Hiramatsu } 1247146a1439SMasami Hiramatsu for (i = 0; i < pev->nargs && ret >= 0; i++) { 1248146a1439SMasami Hiramatsu ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]); 1249146a1439SMasami Hiramatsu if (ret >= 0 && 1250146a1439SMasami Hiramatsu is_c_varname(pev->args[i].var) && pev->point.retprobe) { 12514235b045SMasami Hiramatsu semantic_error("You can't specify local variable for" 1252146a1439SMasami Hiramatsu " kretprobe.\n"); 1253146a1439SMasami Hiramatsu ret = -EINVAL; 1254e1c01d61SMasami Hiramatsu } 1255146a1439SMasami Hiramatsu } 1256146a1439SMasami Hiramatsu out: 1257e1c01d61SMasami Hiramatsu argv_free(argv); 1258146a1439SMasami Hiramatsu 1259146a1439SMasami Hiramatsu return ret; 126050656eecSMasami Hiramatsu } 126150656eecSMasami Hiramatsu 12624235b045SMasami Hiramatsu /* Return true if this perf_probe_event requires debuginfo */ 12634235b045SMasami Hiramatsu bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) 12644de189feSMasami Hiramatsu { 12654235b045SMasami Hiramatsu int i; 12664235b045SMasami Hiramatsu 12674235b045SMasami Hiramatsu if (pev->point.file || pev->point.line || pev->point.lazy_line) 12684235b045SMasami Hiramatsu return true; 12694235b045SMasami Hiramatsu 12704235b045SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) 127148481938SMasami Hiramatsu if (is_c_varname(pev->args[i].var)) 12724235b045SMasami Hiramatsu return true; 12734235b045SMasami Hiramatsu 12744235b045SMasami Hiramatsu return false; 12754235b045SMasami Hiramatsu } 12764235b045SMasami Hiramatsu 12770e60836bSSrikar Dronamraju /* Parse probe_events event into struct probe_point */ 12780e60836bSSrikar Dronamraju static int parse_probe_trace_command(const char *cmd, 12790e60836bSSrikar Dronamraju struct probe_trace_event *tev) 12804235b045SMasami Hiramatsu { 12810e60836bSSrikar Dronamraju struct probe_trace_point *tp = &tev->point; 12824de189feSMasami Hiramatsu char pr; 12834de189feSMasami Hiramatsu char *p; 1284bcbd0040SIrina Tirdea char *argv0_str = NULL, *fmt, *fmt1_str, *fmt2_str, *fmt3_str; 12854de189feSMasami Hiramatsu int ret, i, argc; 12864de189feSMasami Hiramatsu char **argv; 12874de189feSMasami Hiramatsu 12880e60836bSSrikar Dronamraju pr_debug("Parsing probe_events: %s\n", cmd); 12894235b045SMasami Hiramatsu argv = argv_split(cmd, &argc); 1290146a1439SMasami Hiramatsu if (!argv) { 1291146a1439SMasami Hiramatsu pr_debug("Failed to split arguments.\n"); 1292146a1439SMasami Hiramatsu return -ENOMEM; 1293146a1439SMasami Hiramatsu } 1294146a1439SMasami Hiramatsu if (argc < 2) { 1295146a1439SMasami Hiramatsu semantic_error("Too few probe arguments.\n"); 1296146a1439SMasami Hiramatsu ret = -ERANGE; 1297146a1439SMasami Hiramatsu goto out; 1298146a1439SMasami Hiramatsu } 12994de189feSMasami Hiramatsu 13004de189feSMasami Hiramatsu /* Scan event and group name. */ 1301bcbd0040SIrina Tirdea argv0_str = strdup(argv[0]); 1302bcbd0040SIrina Tirdea if (argv0_str == NULL) { 1303bcbd0040SIrina Tirdea ret = -ENOMEM; 1304bcbd0040SIrina Tirdea goto out; 1305bcbd0040SIrina Tirdea } 1306bcbd0040SIrina Tirdea fmt1_str = strtok_r(argv0_str, ":", &fmt); 1307bcbd0040SIrina Tirdea fmt2_str = strtok_r(NULL, "/", &fmt); 1308bcbd0040SIrina Tirdea fmt3_str = strtok_r(NULL, " \t", &fmt); 1309bcbd0040SIrina Tirdea if (fmt1_str == NULL || strlen(fmt1_str) != 1 || fmt2_str == NULL 1310bcbd0040SIrina Tirdea || fmt3_str == NULL) { 1311146a1439SMasami Hiramatsu semantic_error("Failed to parse event name: %s\n", argv[0]); 1312146a1439SMasami Hiramatsu ret = -EINVAL; 1313146a1439SMasami Hiramatsu goto out; 1314146a1439SMasami Hiramatsu } 1315bcbd0040SIrina Tirdea pr = fmt1_str[0]; 1316bcbd0040SIrina Tirdea tev->group = strdup(fmt2_str); 1317bcbd0040SIrina Tirdea tev->event = strdup(fmt3_str); 1318bcbd0040SIrina Tirdea if (tev->group == NULL || tev->event == NULL) { 1319bcbd0040SIrina Tirdea ret = -ENOMEM; 1320bcbd0040SIrina Tirdea goto out; 1321bcbd0040SIrina Tirdea } 13224235b045SMasami Hiramatsu pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr); 13234de189feSMasami Hiramatsu 13244235b045SMasami Hiramatsu tp->retprobe = (pr == 'r'); 13254de189feSMasami Hiramatsu 1326190b57fcSMasami Hiramatsu /* Scan module name(if there), function name and offset */ 1327190b57fcSMasami Hiramatsu p = strchr(argv[1], ':'); 1328190b57fcSMasami Hiramatsu if (p) { 1329190b57fcSMasami Hiramatsu tp->module = strndup(argv[1], p - argv[1]); 1330190b57fcSMasami Hiramatsu p++; 1331190b57fcSMasami Hiramatsu } else 1332190b57fcSMasami Hiramatsu p = argv[1]; 1333bcbd0040SIrina Tirdea fmt1_str = strtok_r(p, "+", &fmt); 13345a6f6314SMasami Hiramatsu if (fmt1_str[0] == '0') /* only the address started with 0x */ 13355a6f6314SMasami Hiramatsu tp->address = strtoul(fmt1_str, NULL, 0); 13365a6f6314SMasami Hiramatsu else { 13375a6f6314SMasami Hiramatsu /* Only the symbol-based probe has offset */ 1338bcbd0040SIrina Tirdea tp->symbol = strdup(fmt1_str); 1339bcbd0040SIrina Tirdea if (tp->symbol == NULL) { 1340bcbd0040SIrina Tirdea ret = -ENOMEM; 1341bcbd0040SIrina Tirdea goto out; 1342bcbd0040SIrina Tirdea } 1343bcbd0040SIrina Tirdea fmt2_str = strtok_r(NULL, "", &fmt); 1344bcbd0040SIrina Tirdea if (fmt2_str == NULL) 13454235b045SMasami Hiramatsu tp->offset = 0; 1346bcbd0040SIrina Tirdea else 1347bcbd0040SIrina Tirdea tp->offset = strtoul(fmt2_str, NULL, 10); 13485a6f6314SMasami Hiramatsu } 13494de189feSMasami Hiramatsu 13504235b045SMasami Hiramatsu tev->nargs = argc - 2; 13510e60836bSSrikar Dronamraju tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1352e334016fSMasami Hiramatsu if (tev->args == NULL) { 1353e334016fSMasami Hiramatsu ret = -ENOMEM; 1354e334016fSMasami Hiramatsu goto out; 1355e334016fSMasami Hiramatsu } 13564235b045SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 13574de189feSMasami Hiramatsu p = strchr(argv[i + 2], '='); 13584de189feSMasami Hiramatsu if (p) /* We don't need which register is assigned. */ 13594235b045SMasami Hiramatsu *p++ = '\0'; 13604235b045SMasami Hiramatsu else 13614235b045SMasami Hiramatsu p = argv[i + 2]; 136202b95dadSMasami Hiramatsu tev->args[i].name = strdup(argv[i + 2]); 13634235b045SMasami Hiramatsu /* TODO: parse regs and offset */ 136402b95dadSMasami Hiramatsu tev->args[i].value = strdup(p); 136502b95dadSMasami Hiramatsu if (tev->args[i].name == NULL || tev->args[i].value == NULL) { 136602b95dadSMasami Hiramatsu ret = -ENOMEM; 136702b95dadSMasami Hiramatsu goto out; 136802b95dadSMasami Hiramatsu } 13694de189feSMasami Hiramatsu } 1370146a1439SMasami Hiramatsu ret = 0; 1371146a1439SMasami Hiramatsu out: 1372bcbd0040SIrina Tirdea free(argv0_str); 13734de189feSMasami Hiramatsu argv_free(argv); 1374146a1439SMasami Hiramatsu return ret; 13754de189feSMasami Hiramatsu } 13764de189feSMasami Hiramatsu 13777df2f329SMasami Hiramatsu /* Compose only probe arg */ 13787df2f329SMasami Hiramatsu int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) 13797df2f329SMasami Hiramatsu { 13807df2f329SMasami Hiramatsu struct perf_probe_arg_field *field = pa->field; 13817df2f329SMasami Hiramatsu int ret; 13827df2f329SMasami Hiramatsu char *tmp = buf; 13837df2f329SMasami Hiramatsu 138448481938SMasami Hiramatsu if (pa->name && pa->var) 138548481938SMasami Hiramatsu ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var); 138648481938SMasami Hiramatsu else 138748481938SMasami Hiramatsu ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var); 13887df2f329SMasami Hiramatsu if (ret <= 0) 13897df2f329SMasami Hiramatsu goto error; 13907df2f329SMasami Hiramatsu tmp += ret; 13917df2f329SMasami Hiramatsu len -= ret; 13927df2f329SMasami Hiramatsu 13937df2f329SMasami Hiramatsu while (field) { 1394b2a3c12bSMasami Hiramatsu if (field->name[0] == '[') 1395b2a3c12bSMasami Hiramatsu ret = e_snprintf(tmp, len, "%s", field->name); 1396b2a3c12bSMasami Hiramatsu else 1397b2a3c12bSMasami Hiramatsu ret = e_snprintf(tmp, len, "%s%s", 1398b2a3c12bSMasami Hiramatsu field->ref ? "->" : ".", field->name); 13997df2f329SMasami Hiramatsu if (ret <= 0) 14007df2f329SMasami Hiramatsu goto error; 14017df2f329SMasami Hiramatsu tmp += ret; 14027df2f329SMasami Hiramatsu len -= ret; 14037df2f329SMasami Hiramatsu field = field->next; 14047df2f329SMasami Hiramatsu } 140511a1ca35SMasami Hiramatsu 140611a1ca35SMasami Hiramatsu if (pa->type) { 140711a1ca35SMasami Hiramatsu ret = e_snprintf(tmp, len, ":%s", pa->type); 140811a1ca35SMasami Hiramatsu if (ret <= 0) 140911a1ca35SMasami Hiramatsu goto error; 141011a1ca35SMasami Hiramatsu tmp += ret; 141111a1ca35SMasami Hiramatsu len -= ret; 141211a1ca35SMasami Hiramatsu } 141311a1ca35SMasami Hiramatsu 14147df2f329SMasami Hiramatsu return tmp - buf; 14157df2f329SMasami Hiramatsu error: 14165f03cba4SMasami Hiramatsu pr_debug("Failed to synthesize perf probe argument: %d\n", ret); 1417146a1439SMasami Hiramatsu return ret; 14187df2f329SMasami Hiramatsu } 14197df2f329SMasami Hiramatsu 14204235b045SMasami Hiramatsu /* Compose only probe point (not argument) */ 14214235b045SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp) 142250656eecSMasami Hiramatsu { 1423fb1587d8SMasami Hiramatsu char *buf, *tmp; 1424fb1587d8SMasami Hiramatsu char offs[32] = "", line[32] = "", file[32] = ""; 1425fb1587d8SMasami Hiramatsu int ret, len; 142650656eecSMasami Hiramatsu 1427e334016fSMasami Hiramatsu buf = zalloc(MAX_CMDLEN); 1428e334016fSMasami Hiramatsu if (buf == NULL) { 1429e334016fSMasami Hiramatsu ret = -ENOMEM; 1430e334016fSMasami Hiramatsu goto error; 1431e334016fSMasami Hiramatsu } 14324de189feSMasami Hiramatsu if (pp->offset) { 1433fb1587d8SMasami Hiramatsu ret = e_snprintf(offs, 32, "+%lu", pp->offset); 14344de189feSMasami Hiramatsu if (ret <= 0) 14354de189feSMasami Hiramatsu goto error; 14364de189feSMasami Hiramatsu } 14374de189feSMasami Hiramatsu if (pp->line) { 1438fb1587d8SMasami Hiramatsu ret = e_snprintf(line, 32, ":%d", pp->line); 1439fb1587d8SMasami Hiramatsu if (ret <= 0) 1440fb1587d8SMasami Hiramatsu goto error; 1441fb1587d8SMasami Hiramatsu } 1442fb1587d8SMasami Hiramatsu if (pp->file) { 144332ae2adeSFranck Bui-Huu tmp = pp->file; 144432ae2adeSFranck Bui-Huu len = strlen(tmp); 144532ae2adeSFranck Bui-Huu if (len > 30) { 144632ae2adeSFranck Bui-Huu tmp = strchr(pp->file + len - 30, '/'); 144732ae2adeSFranck Bui-Huu tmp = tmp ? tmp + 1 : pp->file + len - 30; 144832ae2adeSFranck Bui-Huu } 144932ae2adeSFranck Bui-Huu ret = e_snprintf(file, 32, "@%s", tmp); 14504de189feSMasami Hiramatsu if (ret <= 0) 14514de189feSMasami Hiramatsu goto error; 14524de189feSMasami Hiramatsu } 14534de189feSMasami Hiramatsu 14544de189feSMasami Hiramatsu if (pp->function) 1455fb1587d8SMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function, 1456fb1587d8SMasami Hiramatsu offs, pp->retprobe ? "%return" : "", line, 1457fb1587d8SMasami Hiramatsu file); 14584de189feSMasami Hiramatsu else 1459fb1587d8SMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line); 14604235b045SMasami Hiramatsu if (ret <= 0) 14614235b045SMasami Hiramatsu goto error; 14624235b045SMasami Hiramatsu 14634235b045SMasami Hiramatsu return buf; 14644235b045SMasami Hiramatsu error: 14655f03cba4SMasami Hiramatsu pr_debug("Failed to synthesize perf probe point: %d\n", ret); 1466146a1439SMasami Hiramatsu free(buf); 1467146a1439SMasami Hiramatsu return NULL; 14684235b045SMasami Hiramatsu } 14694235b045SMasami Hiramatsu 14704235b045SMasami Hiramatsu #if 0 14714235b045SMasami Hiramatsu char *synthesize_perf_probe_command(struct perf_probe_event *pev) 14724235b045SMasami Hiramatsu { 14734235b045SMasami Hiramatsu char *buf; 14744235b045SMasami Hiramatsu int i, len, ret; 14754235b045SMasami Hiramatsu 14764235b045SMasami Hiramatsu buf = synthesize_perf_probe_point(&pev->point); 14774235b045SMasami Hiramatsu if (!buf) 14784235b045SMasami Hiramatsu return NULL; 14794235b045SMasami Hiramatsu 14804235b045SMasami Hiramatsu len = strlen(buf); 14814235b045SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) { 14824235b045SMasami Hiramatsu ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 14834235b045SMasami Hiramatsu pev->args[i].name); 14847ef17aafSMasami Hiramatsu if (ret <= 0) { 14854235b045SMasami Hiramatsu free(buf); 14864235b045SMasami Hiramatsu return NULL; 14877ef17aafSMasami Hiramatsu } 14884235b045SMasami Hiramatsu len += ret; 14897ef17aafSMasami Hiramatsu } 149050656eecSMasami Hiramatsu 14914235b045SMasami Hiramatsu return buf; 14924235b045SMasami Hiramatsu } 14934235b045SMasami Hiramatsu #endif 14944235b045SMasami Hiramatsu 14950e60836bSSrikar Dronamraju static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, 14964235b045SMasami Hiramatsu char **buf, size_t *buflen, 14974235b045SMasami Hiramatsu int depth) 14987ef17aafSMasami Hiramatsu { 14994235b045SMasami Hiramatsu int ret; 15004235b045SMasami Hiramatsu if (ref->next) { 15010e60836bSSrikar Dronamraju depth = __synthesize_probe_trace_arg_ref(ref->next, buf, 15024235b045SMasami Hiramatsu buflen, depth + 1); 15034235b045SMasami Hiramatsu if (depth < 0) 15044235b045SMasami Hiramatsu goto out; 15054235b045SMasami Hiramatsu } 15064235b045SMasami Hiramatsu 15074235b045SMasami Hiramatsu ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset); 15084235b045SMasami Hiramatsu if (ret < 0) 15094235b045SMasami Hiramatsu depth = ret; 15104235b045SMasami Hiramatsu else { 15114235b045SMasami Hiramatsu *buf += ret; 15124235b045SMasami Hiramatsu *buflen -= ret; 15134235b045SMasami Hiramatsu } 15144235b045SMasami Hiramatsu out: 15154235b045SMasami Hiramatsu return depth; 15164235b045SMasami Hiramatsu 15174235b045SMasami Hiramatsu } 15184235b045SMasami Hiramatsu 15190e60836bSSrikar Dronamraju static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, 15204235b045SMasami Hiramatsu char *buf, size_t buflen) 15214235b045SMasami Hiramatsu { 15220e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref = arg->ref; 15234235b045SMasami Hiramatsu int ret, depth = 0; 15244235b045SMasami Hiramatsu char *tmp = buf; 15254235b045SMasami Hiramatsu 15264235b045SMasami Hiramatsu /* Argument name or separator */ 15274235b045SMasami Hiramatsu if (arg->name) 15284235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, " %s=", arg->name); 15294235b045SMasami Hiramatsu else 15304235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, " "); 15314235b045SMasami Hiramatsu if (ret < 0) 15324235b045SMasami Hiramatsu return ret; 15334235b045SMasami Hiramatsu buf += ret; 15344235b045SMasami Hiramatsu buflen -= ret; 15354235b045SMasami Hiramatsu 1536b7dcb857SMasami Hiramatsu /* Special case: @XXX */ 1537b7dcb857SMasami Hiramatsu if (arg->value[0] == '@' && arg->ref) 1538b7dcb857SMasami Hiramatsu ref = ref->next; 1539b7dcb857SMasami Hiramatsu 15404235b045SMasami Hiramatsu /* Dereferencing arguments */ 1541b7dcb857SMasami Hiramatsu if (ref) { 15420e60836bSSrikar Dronamraju depth = __synthesize_probe_trace_arg_ref(ref, &buf, 15434235b045SMasami Hiramatsu &buflen, 1); 15444235b045SMasami Hiramatsu if (depth < 0) 15454235b045SMasami Hiramatsu return depth; 15464235b045SMasami Hiramatsu } 15474235b045SMasami Hiramatsu 15484235b045SMasami Hiramatsu /* Print argument value */ 1549b7dcb857SMasami Hiramatsu if (arg->value[0] == '@' && arg->ref) 1550b7dcb857SMasami Hiramatsu ret = e_snprintf(buf, buflen, "%s%+ld", arg->value, 1551b7dcb857SMasami Hiramatsu arg->ref->offset); 1552b7dcb857SMasami Hiramatsu else 15534235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, "%s", arg->value); 15544235b045SMasami Hiramatsu if (ret < 0) 15554235b045SMasami Hiramatsu return ret; 15564235b045SMasami Hiramatsu buf += ret; 15574235b045SMasami Hiramatsu buflen -= ret; 15584235b045SMasami Hiramatsu 15594235b045SMasami Hiramatsu /* Closing */ 15604235b045SMasami Hiramatsu while (depth--) { 15614235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, ")"); 15624235b045SMasami Hiramatsu if (ret < 0) 15634235b045SMasami Hiramatsu return ret; 15644235b045SMasami Hiramatsu buf += ret; 15654235b045SMasami Hiramatsu buflen -= ret; 15664235b045SMasami Hiramatsu } 15674984912eSMasami Hiramatsu /* Print argument type */ 15684984912eSMasami Hiramatsu if (arg->type) { 15694984912eSMasami Hiramatsu ret = e_snprintf(buf, buflen, ":%s", arg->type); 15704984912eSMasami Hiramatsu if (ret <= 0) 15714984912eSMasami Hiramatsu return ret; 15724984912eSMasami Hiramatsu buf += ret; 15734984912eSMasami Hiramatsu } 15744235b045SMasami Hiramatsu 15754235b045SMasami Hiramatsu return buf - tmp; 15764235b045SMasami Hiramatsu } 15774235b045SMasami Hiramatsu 15780e60836bSSrikar Dronamraju char *synthesize_probe_trace_command(struct probe_trace_event *tev) 15794235b045SMasami Hiramatsu { 15800e60836bSSrikar Dronamraju struct probe_trace_point *tp = &tev->point; 15817ef17aafSMasami Hiramatsu char *buf; 15827ef17aafSMasami Hiramatsu int i, len, ret; 15837ef17aafSMasami Hiramatsu 1584e334016fSMasami Hiramatsu buf = zalloc(MAX_CMDLEN); 1585e334016fSMasami Hiramatsu if (buf == NULL) 1586e334016fSMasami Hiramatsu return NULL; 1587e334016fSMasami Hiramatsu 1588eb948e50SMasami Hiramatsu len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p', 1589eb948e50SMasami Hiramatsu tev->group, tev->event); 1590eb948e50SMasami Hiramatsu if (len <= 0) 1591eb948e50SMasami Hiramatsu goto error; 1592eb948e50SMasami Hiramatsu 1593eb948e50SMasami Hiramatsu /* Uprobes must have tp->address and tp->module */ 1594eb948e50SMasami Hiramatsu if (tev->uprobes && (!tp->address || !tp->module)) 1595eb948e50SMasami Hiramatsu goto error; 1596eb948e50SMasami Hiramatsu 1597eb948e50SMasami Hiramatsu /* Use the tp->address for uprobes */ 1598225466f1SSrikar Dronamraju if (tev->uprobes) 1599eb948e50SMasami Hiramatsu ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx", 1600eb948e50SMasami Hiramatsu tp->module, tp->address); 1601225466f1SSrikar Dronamraju else 1602eb948e50SMasami Hiramatsu ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu", 1603190b57fcSMasami Hiramatsu tp->module ?: "", tp->module ? ":" : "", 16044235b045SMasami Hiramatsu tp->symbol, tp->offset); 1605225466f1SSrikar Dronamraju 1606eb948e50SMasami Hiramatsu if (ret <= 0) 16074235b045SMasami Hiramatsu goto error; 1608eb948e50SMasami Hiramatsu len += ret; 16097ef17aafSMasami Hiramatsu 16104235b045SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 16110e60836bSSrikar Dronamraju ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, 16124235b045SMasami Hiramatsu MAX_CMDLEN - len); 16134de189feSMasami Hiramatsu if (ret <= 0) 161450656eecSMasami Hiramatsu goto error; 161550656eecSMasami Hiramatsu len += ret; 161650656eecSMasami Hiramatsu } 161750656eecSMasami Hiramatsu 16184235b045SMasami Hiramatsu return buf; 161950656eecSMasami Hiramatsu error: 16204235b045SMasami Hiramatsu free(buf); 16214235b045SMasami Hiramatsu return NULL; 162250656eecSMasami Hiramatsu } 162350656eecSMasami Hiramatsu 16245a6f6314SMasami Hiramatsu static int find_perf_probe_point_from_map(struct probe_trace_point *tp, 16255a6f6314SMasami Hiramatsu struct perf_probe_point *pp, 16265a6f6314SMasami Hiramatsu bool is_kprobe) 16275a6f6314SMasami Hiramatsu { 16285a6f6314SMasami Hiramatsu struct symbol *sym = NULL; 16295a6f6314SMasami Hiramatsu struct map *map; 16305a6f6314SMasami Hiramatsu u64 addr; 16315a6f6314SMasami Hiramatsu int ret = -ENOENT; 16325a6f6314SMasami Hiramatsu 16335a6f6314SMasami Hiramatsu if (!is_kprobe) { 16345a6f6314SMasami Hiramatsu map = dso__new_map(tp->module); 16355a6f6314SMasami Hiramatsu if (!map) 16365a6f6314SMasami Hiramatsu goto out; 16375a6f6314SMasami Hiramatsu addr = tp->address; 16385a6f6314SMasami Hiramatsu sym = map__find_symbol(map, addr, NULL); 16395a6f6314SMasami Hiramatsu } else { 16405a6f6314SMasami Hiramatsu addr = kernel_get_symbol_address_by_name(tp->symbol, true); 16415a6f6314SMasami Hiramatsu if (addr) { 16425a6f6314SMasami Hiramatsu addr += tp->offset; 16435a6f6314SMasami Hiramatsu sym = __find_kernel_function(addr, &map); 16445a6f6314SMasami Hiramatsu } 16455a6f6314SMasami Hiramatsu } 16465a6f6314SMasami Hiramatsu if (!sym) 16475a6f6314SMasami Hiramatsu goto out; 16485a6f6314SMasami Hiramatsu 16495a6f6314SMasami Hiramatsu pp->retprobe = tp->retprobe; 16505a6f6314SMasami Hiramatsu pp->offset = addr - map->unmap_ip(map, sym->start); 16515a6f6314SMasami Hiramatsu pp->function = strdup(sym->name); 16525a6f6314SMasami Hiramatsu ret = pp->function ? 0 : -ENOMEM; 16535a6f6314SMasami Hiramatsu 16545a6f6314SMasami Hiramatsu out: 16555a6f6314SMasami Hiramatsu if (map && !is_kprobe) { 16565a6f6314SMasami Hiramatsu dso__delete(map->dso); 16575a6f6314SMasami Hiramatsu map__delete(map); 16585a6f6314SMasami Hiramatsu } 16595a6f6314SMasami Hiramatsu 16605a6f6314SMasami Hiramatsu return ret; 16615a6f6314SMasami Hiramatsu } 16625a6f6314SMasami Hiramatsu 16635a6f6314SMasami Hiramatsu static int convert_to_perf_probe_point(struct probe_trace_point *tp, 16645a6f6314SMasami Hiramatsu struct perf_probe_point *pp, 16655a6f6314SMasami Hiramatsu bool is_kprobe) 16665a6f6314SMasami Hiramatsu { 16675a6f6314SMasami Hiramatsu char buf[128]; 16685a6f6314SMasami Hiramatsu int ret; 16695a6f6314SMasami Hiramatsu 16705a6f6314SMasami Hiramatsu ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe); 16715a6f6314SMasami Hiramatsu if (!ret) 16725a6f6314SMasami Hiramatsu return 0; 16735a6f6314SMasami Hiramatsu ret = find_perf_probe_point_from_map(tp, pp, is_kprobe); 16745a6f6314SMasami Hiramatsu if (!ret) 16755a6f6314SMasami Hiramatsu return 0; 16765a6f6314SMasami Hiramatsu 16775a6f6314SMasami Hiramatsu pr_debug("Failed to find probe point from both of dwarf and map.\n"); 16785a6f6314SMasami Hiramatsu 16795a6f6314SMasami Hiramatsu if (tp->symbol) { 16805a6f6314SMasami Hiramatsu pp->function = strdup(tp->symbol); 16815a6f6314SMasami Hiramatsu pp->offset = tp->offset; 16825a6f6314SMasami Hiramatsu } else if (!tp->module && !is_kprobe) { 16835a6f6314SMasami Hiramatsu ret = e_snprintf(buf, 128, "0x%" PRIx64, (u64)tp->address); 16845a6f6314SMasami Hiramatsu if (ret < 0) 16855a6f6314SMasami Hiramatsu return ret; 16865a6f6314SMasami Hiramatsu pp->function = strdup(buf); 16875a6f6314SMasami Hiramatsu pp->offset = 0; 16885a6f6314SMasami Hiramatsu } 16895a6f6314SMasami Hiramatsu if (pp->function == NULL) 16905a6f6314SMasami Hiramatsu return -ENOMEM; 16915a6f6314SMasami Hiramatsu 16925a6f6314SMasami Hiramatsu pp->retprobe = tp->retprobe; 16935a6f6314SMasami Hiramatsu 16945a6f6314SMasami Hiramatsu return 0; 16955a6f6314SMasami Hiramatsu } 16965a6f6314SMasami Hiramatsu 16970e60836bSSrikar Dronamraju static int convert_to_perf_probe_event(struct probe_trace_event *tev, 1698225466f1SSrikar Dronamraju struct perf_probe_event *pev, bool is_kprobe) 16994de189feSMasami Hiramatsu { 170002b95dadSMasami Hiramatsu char buf[64] = ""; 1701146a1439SMasami Hiramatsu int i, ret; 17024de189feSMasami Hiramatsu 17034b4da7f7SMasami Hiramatsu /* Convert event/group name */ 170402b95dadSMasami Hiramatsu pev->event = strdup(tev->event); 170502b95dadSMasami Hiramatsu pev->group = strdup(tev->group); 170602b95dadSMasami Hiramatsu if (pev->event == NULL || pev->group == NULL) 170702b95dadSMasami Hiramatsu return -ENOMEM; 1708fb1587d8SMasami Hiramatsu 17094b4da7f7SMasami Hiramatsu /* Convert trace_point to probe_point */ 17105a6f6314SMasami Hiramatsu ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe); 1711146a1439SMasami Hiramatsu if (ret < 0) 1712146a1439SMasami Hiramatsu return ret; 17134b4da7f7SMasami Hiramatsu 17144235b045SMasami Hiramatsu /* Convert trace_arg to probe_arg */ 17154235b045SMasami Hiramatsu pev->nargs = tev->nargs; 1716e334016fSMasami Hiramatsu pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); 1717e334016fSMasami Hiramatsu if (pev->args == NULL) 1718e334016fSMasami Hiramatsu return -ENOMEM; 171902b95dadSMasami Hiramatsu for (i = 0; i < tev->nargs && ret >= 0; i++) { 17204235b045SMasami Hiramatsu if (tev->args[i].name) 172102b95dadSMasami Hiramatsu pev->args[i].name = strdup(tev->args[i].name); 17224235b045SMasami Hiramatsu else { 17230e60836bSSrikar Dronamraju ret = synthesize_probe_trace_arg(&tev->args[i], 1724146a1439SMasami Hiramatsu buf, 64); 172502b95dadSMasami Hiramatsu pev->args[i].name = strdup(buf); 172602b95dadSMasami Hiramatsu } 172702b95dadSMasami Hiramatsu if (pev->args[i].name == NULL && ret >= 0) 172802b95dadSMasami Hiramatsu ret = -ENOMEM; 17294de189feSMasami Hiramatsu } 1730146a1439SMasami Hiramatsu 1731146a1439SMasami Hiramatsu if (ret < 0) 1732146a1439SMasami Hiramatsu clear_perf_probe_event(pev); 1733146a1439SMasami Hiramatsu 1734146a1439SMasami Hiramatsu return ret; 17354235b045SMasami Hiramatsu } 17364de189feSMasami Hiramatsu 17374235b045SMasami Hiramatsu void clear_perf_probe_event(struct perf_probe_event *pev) 17384235b045SMasami Hiramatsu { 17394235b045SMasami Hiramatsu struct perf_probe_point *pp = &pev->point; 17407df2f329SMasami Hiramatsu struct perf_probe_arg_field *field, *next; 17414235b045SMasami Hiramatsu int i; 17424de189feSMasami Hiramatsu 17434235b045SMasami Hiramatsu free(pev->event); 17444235b045SMasami Hiramatsu free(pev->group); 17454235b045SMasami Hiramatsu free(pp->file); 17464235b045SMasami Hiramatsu free(pp->function); 17474235b045SMasami Hiramatsu free(pp->lazy_line); 1748f5385650SArnaldo Carvalho de Melo 17497df2f329SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) { 17504235b045SMasami Hiramatsu free(pev->args[i].name); 175148481938SMasami Hiramatsu free(pev->args[i].var); 175211a1ca35SMasami Hiramatsu free(pev->args[i].type); 17537df2f329SMasami Hiramatsu field = pev->args[i].field; 17547df2f329SMasami Hiramatsu while (field) { 17557df2f329SMasami Hiramatsu next = field->next; 175674cf249dSArnaldo Carvalho de Melo zfree(&field->name); 17577df2f329SMasami Hiramatsu free(field); 17587df2f329SMasami Hiramatsu field = next; 17597df2f329SMasami Hiramatsu } 17607df2f329SMasami Hiramatsu } 17614235b045SMasami Hiramatsu free(pev->args); 17624235b045SMasami Hiramatsu memset(pev, 0, sizeof(*pev)); 17634235b045SMasami Hiramatsu } 17644235b045SMasami Hiramatsu 17650e60836bSSrikar Dronamraju static void clear_probe_trace_event(struct probe_trace_event *tev) 17664235b045SMasami Hiramatsu { 17670e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref, *next; 17684235b045SMasami Hiramatsu int i; 17694235b045SMasami Hiramatsu 17704235b045SMasami Hiramatsu free(tev->event); 17714235b045SMasami Hiramatsu free(tev->group); 17724235b045SMasami Hiramatsu free(tev->point.symbol); 1773190b57fcSMasami Hiramatsu free(tev->point.module); 17744235b045SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 17754235b045SMasami Hiramatsu free(tev->args[i].name); 17764235b045SMasami Hiramatsu free(tev->args[i].value); 17774984912eSMasami Hiramatsu free(tev->args[i].type); 17784235b045SMasami Hiramatsu ref = tev->args[i].ref; 17794235b045SMasami Hiramatsu while (ref) { 17804235b045SMasami Hiramatsu next = ref->next; 17814235b045SMasami Hiramatsu free(ref); 17824235b045SMasami Hiramatsu ref = next; 17834235b045SMasami Hiramatsu } 17844235b045SMasami Hiramatsu } 17854235b045SMasami Hiramatsu free(tev->args); 17864235b045SMasami Hiramatsu memset(tev, 0, sizeof(*tev)); 17874de189feSMasami Hiramatsu } 17884de189feSMasami Hiramatsu 17895e45187cSMasami Hiramatsu static void print_open_warning(int err, bool is_kprobe) 1790225466f1SSrikar Dronamraju { 17915f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 1792225466f1SSrikar Dronamraju 17935e45187cSMasami Hiramatsu if (err == -ENOENT) { 1794225466f1SSrikar Dronamraju const char *config; 1795225466f1SSrikar Dronamraju 1796225466f1SSrikar Dronamraju if (!is_kprobe) 1797225466f1SSrikar Dronamraju config = "CONFIG_UPROBE_EVENTS"; 1798225466f1SSrikar Dronamraju else 1799225466f1SSrikar Dronamraju config = "CONFIG_KPROBE_EVENTS"; 1800225466f1SSrikar Dronamraju 18015e45187cSMasami Hiramatsu pr_warning("%cprobe_events file does not exist" 18025e45187cSMasami Hiramatsu " - please rebuild kernel with %s.\n", 18035e45187cSMasami Hiramatsu is_kprobe ? 'k' : 'u', config); 18045e45187cSMasami Hiramatsu } else if (err == -ENOTSUP) 18055e45187cSMasami Hiramatsu pr_warning("Debugfs is not mounted.\n"); 18065e45187cSMasami Hiramatsu else 18075e45187cSMasami Hiramatsu pr_warning("Failed to open %cprobe_events: %s\n", 18085e45187cSMasami Hiramatsu is_kprobe ? 'k' : 'u', 18095e45187cSMasami Hiramatsu strerror_r(-err, sbuf, sizeof(sbuf))); 1810225466f1SSrikar Dronamraju } 1811225466f1SSrikar Dronamraju 1812467ec085SMasami Hiramatsu static void print_both_open_warning(int kerr, int uerr) 1813467ec085SMasami Hiramatsu { 1814467ec085SMasami Hiramatsu /* Both kprobes and uprobes are disabled, warn it. */ 1815467ec085SMasami Hiramatsu if (kerr == -ENOTSUP && uerr == -ENOTSUP) 1816467ec085SMasami Hiramatsu pr_warning("Debugfs is not mounted.\n"); 1817467ec085SMasami Hiramatsu else if (kerr == -ENOENT && uerr == -ENOENT) 1818467ec085SMasami Hiramatsu pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS " 1819467ec085SMasami Hiramatsu "or/and CONFIG_UPROBE_EVENTS.\n"); 1820467ec085SMasami Hiramatsu else { 18215f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 1822467ec085SMasami Hiramatsu pr_warning("Failed to open kprobe events: %s.\n", 1823467ec085SMasami Hiramatsu strerror_r(-kerr, sbuf, sizeof(sbuf))); 1824467ec085SMasami Hiramatsu pr_warning("Failed to open uprobe events: %s.\n", 1825467ec085SMasami Hiramatsu strerror_r(-uerr, sbuf, sizeof(sbuf))); 1826467ec085SMasami Hiramatsu } 1827467ec085SMasami Hiramatsu } 1828467ec085SMasami Hiramatsu 18295e45187cSMasami Hiramatsu static int open_probe_events(const char *trace_file, bool readwrite) 18304de189feSMasami Hiramatsu { 18314de189feSMasami Hiramatsu char buf[PATH_MAX]; 18327ca5989dSMasami Hiramatsu const char *__debugfs; 18334de189feSMasami Hiramatsu int ret; 18344de189feSMasami Hiramatsu 18357ca5989dSMasami Hiramatsu __debugfs = debugfs_find_mountpoint(); 18365e45187cSMasami Hiramatsu if (__debugfs == NULL) 18375e45187cSMasami Hiramatsu return -ENOTSUP; 18387ca5989dSMasami Hiramatsu 1839225466f1SSrikar Dronamraju ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file); 1840146a1439SMasami Hiramatsu if (ret >= 0) { 18417ca5989dSMasami Hiramatsu pr_debug("Opening %s write=%d\n", buf, readwrite); 1842f4d7da49SMasami Hiramatsu if (readwrite && !probe_event_dry_run) 1843f4d7da49SMasami Hiramatsu ret = open(buf, O_RDWR, O_APPEND); 1844f4d7da49SMasami Hiramatsu else 1845f4d7da49SMasami Hiramatsu ret = open(buf, O_RDONLY, 0); 1846f4d7da49SMasami Hiramatsu 1847225466f1SSrikar Dronamraju if (ret < 0) 18485e45187cSMasami Hiramatsu ret = -errno; 18494de189feSMasami Hiramatsu } 18504de189feSMasami Hiramatsu return ret; 18514de189feSMasami Hiramatsu } 18524de189feSMasami Hiramatsu 1853225466f1SSrikar Dronamraju static int open_kprobe_events(bool readwrite) 1854225466f1SSrikar Dronamraju { 18555e45187cSMasami Hiramatsu return open_probe_events("tracing/kprobe_events", readwrite); 1856225466f1SSrikar Dronamraju } 1857225466f1SSrikar Dronamraju 1858225466f1SSrikar Dronamraju static int open_uprobe_events(bool readwrite) 1859225466f1SSrikar Dronamraju { 18605e45187cSMasami Hiramatsu return open_probe_events("tracing/uprobe_events", readwrite); 1861225466f1SSrikar Dronamraju } 1862225466f1SSrikar Dronamraju 1863225466f1SSrikar Dronamraju /* Get raw string list of current kprobe_events or uprobe_events */ 18640e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_command_rawlist(int fd) 18654de189feSMasami Hiramatsu { 18664de189feSMasami Hiramatsu int ret, idx; 18674de189feSMasami Hiramatsu FILE *fp; 18684de189feSMasami Hiramatsu char buf[MAX_CMDLEN]; 18694de189feSMasami Hiramatsu char *p; 18704de189feSMasami Hiramatsu struct strlist *sl; 18714de189feSMasami Hiramatsu 18724de189feSMasami Hiramatsu sl = strlist__new(true, NULL); 18734de189feSMasami Hiramatsu 18744de189feSMasami Hiramatsu fp = fdopen(dup(fd), "r"); 18754de189feSMasami Hiramatsu while (!feof(fp)) { 18764de189feSMasami Hiramatsu p = fgets(buf, MAX_CMDLEN, fp); 18774de189feSMasami Hiramatsu if (!p) 18784de189feSMasami Hiramatsu break; 18794de189feSMasami Hiramatsu 18804de189feSMasami Hiramatsu idx = strlen(p) - 1; 18814de189feSMasami Hiramatsu if (p[idx] == '\n') 18824de189feSMasami Hiramatsu p[idx] = '\0'; 18834de189feSMasami Hiramatsu ret = strlist__add(sl, buf); 1884146a1439SMasami Hiramatsu if (ret < 0) { 18856eb08660SMasami Hiramatsu pr_debug("strlist__add failed (%d)\n", ret); 1886146a1439SMasami Hiramatsu strlist__delete(sl); 1887146a1439SMasami Hiramatsu return NULL; 1888146a1439SMasami Hiramatsu } 18894de189feSMasami Hiramatsu } 18904de189feSMasami Hiramatsu fclose(fp); 18914de189feSMasami Hiramatsu 18924de189feSMasami Hiramatsu return sl; 18934de189feSMasami Hiramatsu } 18944de189feSMasami Hiramatsu 1895278498d4SMasami Hiramatsu /* Show an event */ 1896fb226ccdSMasami Hiramatsu static int show_perf_probe_event(struct perf_probe_event *pev, 1897fb226ccdSMasami Hiramatsu const char *module) 1898278498d4SMasami Hiramatsu { 18997e990a51SMasami Hiramatsu int i, ret; 1900278498d4SMasami Hiramatsu char buf[128]; 19014235b045SMasami Hiramatsu char *place; 1902278498d4SMasami Hiramatsu 19034235b045SMasami Hiramatsu /* Synthesize only event probe point */ 19044235b045SMasami Hiramatsu place = synthesize_perf_probe_point(&pev->point); 1905146a1439SMasami Hiramatsu if (!place) 1906146a1439SMasami Hiramatsu return -EINVAL; 19074235b045SMasami Hiramatsu 19084235b045SMasami Hiramatsu ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); 19097e990a51SMasami Hiramatsu if (ret < 0) 1910146a1439SMasami Hiramatsu return ret; 1911146a1439SMasami Hiramatsu 1912fb1587d8SMasami Hiramatsu printf(" %-20s (on %s", buf, place); 1913fb226ccdSMasami Hiramatsu if (module) 1914fb226ccdSMasami Hiramatsu printf(" in %s", module); 1915278498d4SMasami Hiramatsu 19164235b045SMasami Hiramatsu if (pev->nargs > 0) { 1917278498d4SMasami Hiramatsu printf(" with"); 19187df2f329SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) { 1919146a1439SMasami Hiramatsu ret = synthesize_perf_probe_arg(&pev->args[i], 1920146a1439SMasami Hiramatsu buf, 128); 1921146a1439SMasami Hiramatsu if (ret < 0) 1922146a1439SMasami Hiramatsu break; 19237df2f329SMasami Hiramatsu printf(" %s", buf); 19247df2f329SMasami Hiramatsu } 1925278498d4SMasami Hiramatsu } 1926278498d4SMasami Hiramatsu printf(")\n"); 19274235b045SMasami Hiramatsu free(place); 1928146a1439SMasami Hiramatsu return ret; 1929278498d4SMasami Hiramatsu } 1930278498d4SMasami Hiramatsu 1931225466f1SSrikar Dronamraju static int __show_perf_probe_events(int fd, bool is_kprobe) 19324de189feSMasami Hiramatsu { 1933225466f1SSrikar Dronamraju int ret = 0; 19340e60836bSSrikar Dronamraju struct probe_trace_event tev; 19354235b045SMasami Hiramatsu struct perf_probe_event pev; 19364de189feSMasami Hiramatsu struct strlist *rawlist; 19374de189feSMasami Hiramatsu struct str_node *ent; 19384de189feSMasami Hiramatsu 19394235b045SMasami Hiramatsu memset(&tev, 0, sizeof(tev)); 19404235b045SMasami Hiramatsu memset(&pev, 0, sizeof(pev)); 194172041334SMasami Hiramatsu 19420e60836bSSrikar Dronamraju rawlist = get_probe_trace_command_rawlist(fd); 1943146a1439SMasami Hiramatsu if (!rawlist) 19446eb08660SMasami Hiramatsu return -ENOMEM; 19454de189feSMasami Hiramatsu 1946adf365f4SMasami Hiramatsu strlist__for_each(ent, rawlist) { 19470e60836bSSrikar Dronamraju ret = parse_probe_trace_command(ent->s, &tev); 1948146a1439SMasami Hiramatsu if (ret >= 0) { 1949225466f1SSrikar Dronamraju ret = convert_to_perf_probe_event(&tev, &pev, 1950225466f1SSrikar Dronamraju is_kprobe); 1951146a1439SMasami Hiramatsu if (ret >= 0) 1952fb226ccdSMasami Hiramatsu ret = show_perf_probe_event(&pev, 1953fb226ccdSMasami Hiramatsu tev.point.module); 1954146a1439SMasami Hiramatsu } 19554235b045SMasami Hiramatsu clear_perf_probe_event(&pev); 19560e60836bSSrikar Dronamraju clear_probe_trace_event(&tev); 1957146a1439SMasami Hiramatsu if (ret < 0) 1958146a1439SMasami Hiramatsu break; 19594de189feSMasami Hiramatsu } 19604de189feSMasami Hiramatsu strlist__delete(rawlist); 1961146a1439SMasami Hiramatsu 1962146a1439SMasami Hiramatsu return ret; 19634de189feSMasami Hiramatsu } 19644de189feSMasami Hiramatsu 1965225466f1SSrikar Dronamraju /* List up current perf-probe events */ 1966225466f1SSrikar Dronamraju int show_perf_probe_events(void) 1967225466f1SSrikar Dronamraju { 19685e45187cSMasami Hiramatsu int kp_fd, up_fd, ret; 1969225466f1SSrikar Dronamraju 1970225466f1SSrikar Dronamraju setup_pager(); 1971225466f1SSrikar Dronamraju 1972ee45b6c2SMasami Hiramatsu ret = init_symbol_maps(false); 1973225466f1SSrikar Dronamraju if (ret < 0) 1974225466f1SSrikar Dronamraju return ret; 1975225466f1SSrikar Dronamraju 19765e45187cSMasami Hiramatsu kp_fd = open_kprobe_events(false); 19775e45187cSMasami Hiramatsu if (kp_fd >= 0) { 19785e45187cSMasami Hiramatsu ret = __show_perf_probe_events(kp_fd, true); 19795e45187cSMasami Hiramatsu close(kp_fd); 19805e45187cSMasami Hiramatsu if (ret < 0) 19815e45187cSMasami Hiramatsu goto out; 1982225466f1SSrikar Dronamraju } 1983225466f1SSrikar Dronamraju 19845e45187cSMasami Hiramatsu up_fd = open_uprobe_events(false); 19855e45187cSMasami Hiramatsu if (kp_fd < 0 && up_fd < 0) { 1986467ec085SMasami Hiramatsu print_both_open_warning(kp_fd, up_fd); 19875e45187cSMasami Hiramatsu ret = kp_fd; 19885e45187cSMasami Hiramatsu goto out; 19895e45187cSMasami Hiramatsu } 19905e45187cSMasami Hiramatsu 19915e45187cSMasami Hiramatsu if (up_fd >= 0) { 19925e45187cSMasami Hiramatsu ret = __show_perf_probe_events(up_fd, false); 19935e45187cSMasami Hiramatsu close(up_fd); 19945e45187cSMasami Hiramatsu } 19955e45187cSMasami Hiramatsu out: 1996ee45b6c2SMasami Hiramatsu exit_symbol_maps(); 1997225466f1SSrikar Dronamraju return ret; 1998225466f1SSrikar Dronamraju } 1999225466f1SSrikar Dronamraju 2000b498ce1fSMasami Hiramatsu /* Get current perf-probe event names */ 20010e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_event_names(int fd, bool include_group) 2002b498ce1fSMasami Hiramatsu { 2003fa28244dSMasami Hiramatsu char buf[128]; 2004b498ce1fSMasami Hiramatsu struct strlist *sl, *rawlist; 2005b498ce1fSMasami Hiramatsu struct str_node *ent; 20060e60836bSSrikar Dronamraju struct probe_trace_event tev; 2007146a1439SMasami Hiramatsu int ret = 0; 2008b498ce1fSMasami Hiramatsu 20094235b045SMasami Hiramatsu memset(&tev, 0, sizeof(tev)); 20100e60836bSSrikar Dronamraju rawlist = get_probe_trace_command_rawlist(fd); 20116eb08660SMasami Hiramatsu if (!rawlist) 20126eb08660SMasami Hiramatsu return NULL; 2013e1d2017bSMasami Hiramatsu sl = strlist__new(true, NULL); 2014adf365f4SMasami Hiramatsu strlist__for_each(ent, rawlist) { 20150e60836bSSrikar Dronamraju ret = parse_probe_trace_command(ent->s, &tev); 2016146a1439SMasami Hiramatsu if (ret < 0) 2017146a1439SMasami Hiramatsu break; 2018fa28244dSMasami Hiramatsu if (include_group) { 2019146a1439SMasami Hiramatsu ret = e_snprintf(buf, 128, "%s:%s", tev.group, 2020146a1439SMasami Hiramatsu tev.event); 2021146a1439SMasami Hiramatsu if (ret >= 0) 2022146a1439SMasami Hiramatsu ret = strlist__add(sl, buf); 2023fa28244dSMasami Hiramatsu } else 2024146a1439SMasami Hiramatsu ret = strlist__add(sl, tev.event); 20250e60836bSSrikar Dronamraju clear_probe_trace_event(&tev); 2026146a1439SMasami Hiramatsu if (ret < 0) 2027146a1439SMasami Hiramatsu break; 2028b498ce1fSMasami Hiramatsu } 2029b498ce1fSMasami Hiramatsu strlist__delete(rawlist); 2030b498ce1fSMasami Hiramatsu 2031146a1439SMasami Hiramatsu if (ret < 0) { 2032146a1439SMasami Hiramatsu strlist__delete(sl); 2033146a1439SMasami Hiramatsu return NULL; 2034146a1439SMasami Hiramatsu } 2035b498ce1fSMasami Hiramatsu return sl; 2036b498ce1fSMasami Hiramatsu } 2037b498ce1fSMasami Hiramatsu 20380e60836bSSrikar Dronamraju static int write_probe_trace_event(int fd, struct probe_trace_event *tev) 203950656eecSMasami Hiramatsu { 20406eca8cc3SFrederic Weisbecker int ret = 0; 20410e60836bSSrikar Dronamraju char *buf = synthesize_probe_trace_command(tev); 20425f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 204350656eecSMasami Hiramatsu 2044146a1439SMasami Hiramatsu if (!buf) { 20450e60836bSSrikar Dronamraju pr_debug("Failed to synthesize probe trace event.\n"); 2046146a1439SMasami Hiramatsu return -EINVAL; 2047146a1439SMasami Hiramatsu } 2048146a1439SMasami Hiramatsu 2049fa28244dSMasami Hiramatsu pr_debug("Writing event: %s\n", buf); 2050f4d7da49SMasami Hiramatsu if (!probe_event_dry_run) { 205150656eecSMasami Hiramatsu ret = write(fd, buf, strlen(buf)); 205250656eecSMasami Hiramatsu if (ret <= 0) 2053146a1439SMasami Hiramatsu pr_warning("Failed to write event: %s\n", 20545f03cba4SMasami Hiramatsu strerror_r(errno, sbuf, sizeof(sbuf))); 205550656eecSMasami Hiramatsu } 20564235b045SMasami Hiramatsu free(buf); 2057146a1439SMasami Hiramatsu return ret; 2058f4d7da49SMasami Hiramatsu } 205950656eecSMasami Hiramatsu 2060146a1439SMasami Hiramatsu static int get_new_event_name(char *buf, size_t len, const char *base, 2061d761b08bSMasami Hiramatsu struct strlist *namelist, bool allow_suffix) 2062b498ce1fSMasami Hiramatsu { 2063b498ce1fSMasami Hiramatsu int i, ret; 206417f88fcdSMasami Hiramatsu 206517f88fcdSMasami Hiramatsu /* Try no suffix */ 206617f88fcdSMasami Hiramatsu ret = e_snprintf(buf, len, "%s", base); 2067146a1439SMasami Hiramatsu if (ret < 0) { 20685f03cba4SMasami Hiramatsu pr_debug("snprintf() failed: %d\n", ret); 2069146a1439SMasami Hiramatsu return ret; 2070146a1439SMasami Hiramatsu } 207117f88fcdSMasami Hiramatsu if (!strlist__has_entry(namelist, buf)) 2072146a1439SMasami Hiramatsu return 0; 207317f88fcdSMasami Hiramatsu 2074d761b08bSMasami Hiramatsu if (!allow_suffix) { 2075d761b08bSMasami Hiramatsu pr_warning("Error: event \"%s\" already exists. " 2076d761b08bSMasami Hiramatsu "(Use -f to force duplicates.)\n", base); 2077146a1439SMasami Hiramatsu return -EEXIST; 2078d761b08bSMasami Hiramatsu } 2079d761b08bSMasami Hiramatsu 208017f88fcdSMasami Hiramatsu /* Try to add suffix */ 208117f88fcdSMasami Hiramatsu for (i = 1; i < MAX_EVENT_INDEX; i++) { 2082b498ce1fSMasami Hiramatsu ret = e_snprintf(buf, len, "%s_%d", base, i); 2083146a1439SMasami Hiramatsu if (ret < 0) { 20845f03cba4SMasami Hiramatsu pr_debug("snprintf() failed: %d\n", ret); 2085146a1439SMasami Hiramatsu return ret; 2086146a1439SMasami Hiramatsu } 2087b498ce1fSMasami Hiramatsu if (!strlist__has_entry(namelist, buf)) 2088b498ce1fSMasami Hiramatsu break; 2089b498ce1fSMasami Hiramatsu } 2090146a1439SMasami Hiramatsu if (i == MAX_EVENT_INDEX) { 2091146a1439SMasami Hiramatsu pr_warning("Too many events are on the same function.\n"); 2092146a1439SMasami Hiramatsu ret = -ERANGE; 2093b498ce1fSMasami Hiramatsu } 2094b498ce1fSMasami Hiramatsu 2095146a1439SMasami Hiramatsu return ret; 2096146a1439SMasami Hiramatsu } 2097146a1439SMasami Hiramatsu 20980e60836bSSrikar Dronamraju static int __add_probe_trace_events(struct perf_probe_event *pev, 20990e60836bSSrikar Dronamraju struct probe_trace_event *tevs, 21004235b045SMasami Hiramatsu int ntevs, bool allow_suffix) 210150656eecSMasami Hiramatsu { 2102146a1439SMasami Hiramatsu int i, fd, ret; 21030e60836bSSrikar Dronamraju struct probe_trace_event *tev = NULL; 21044235b045SMasami Hiramatsu char buf[64]; 21054235b045SMasami Hiramatsu const char *event, *group; 2106b498ce1fSMasami Hiramatsu struct strlist *namelist; 210750656eecSMasami Hiramatsu 2108225466f1SSrikar Dronamraju if (pev->uprobes) 2109225466f1SSrikar Dronamraju fd = open_uprobe_events(true); 2110225466f1SSrikar Dronamraju else 2111f4d7da49SMasami Hiramatsu fd = open_kprobe_events(true); 2112225466f1SSrikar Dronamraju 21135e45187cSMasami Hiramatsu if (fd < 0) { 21145e45187cSMasami Hiramatsu print_open_warning(fd, !pev->uprobes); 2115146a1439SMasami Hiramatsu return fd; 21165e45187cSMasami Hiramatsu } 21175e45187cSMasami Hiramatsu 2118b498ce1fSMasami Hiramatsu /* Get current event names */ 21190e60836bSSrikar Dronamraju namelist = get_probe_trace_event_names(fd, false); 2120146a1439SMasami Hiramatsu if (!namelist) { 2121146a1439SMasami Hiramatsu pr_debug("Failed to get current event list.\n"); 2122146a1439SMasami Hiramatsu return -EIO; 2123146a1439SMasami Hiramatsu } 212450656eecSMasami Hiramatsu 2125146a1439SMasami Hiramatsu ret = 0; 2126a844d1efSSrikar Dronamraju printf("Added new event%s\n", (ntevs > 1) ? "s:" : ":"); 212702b95dadSMasami Hiramatsu for (i = 0; i < ntevs; i++) { 21284235b045SMasami Hiramatsu tev = &tevs[i]; 21294235b045SMasami Hiramatsu if (pev->event) 21304235b045SMasami Hiramatsu event = pev->event; 21314235b045SMasami Hiramatsu else 21324235b045SMasami Hiramatsu if (pev->point.function) 21334235b045SMasami Hiramatsu event = pev->point.function; 21344235b045SMasami Hiramatsu else 21354235b045SMasami Hiramatsu event = tev->point.symbol; 21364235b045SMasami Hiramatsu if (pev->group) 21374235b045SMasami Hiramatsu group = pev->group; 21384235b045SMasami Hiramatsu else 21394235b045SMasami Hiramatsu group = PERFPROBE_GROUP; 21404235b045SMasami Hiramatsu 2141b498ce1fSMasami Hiramatsu /* Get an unused new event name */ 2142146a1439SMasami Hiramatsu ret = get_new_event_name(buf, 64, event, 2143146a1439SMasami Hiramatsu namelist, allow_suffix); 2144146a1439SMasami Hiramatsu if (ret < 0) 2145146a1439SMasami Hiramatsu break; 21464235b045SMasami Hiramatsu event = buf; 21474235b045SMasami Hiramatsu 214802b95dadSMasami Hiramatsu tev->event = strdup(event); 214902b95dadSMasami Hiramatsu tev->group = strdup(group); 215002b95dadSMasami Hiramatsu if (tev->event == NULL || tev->group == NULL) { 215102b95dadSMasami Hiramatsu ret = -ENOMEM; 215202b95dadSMasami Hiramatsu break; 215302b95dadSMasami Hiramatsu } 21540e60836bSSrikar Dronamraju ret = write_probe_trace_event(fd, tev); 2155146a1439SMasami Hiramatsu if (ret < 0) 2156146a1439SMasami Hiramatsu break; 2157b498ce1fSMasami Hiramatsu /* Add added event name to namelist */ 2158b498ce1fSMasami Hiramatsu strlist__add(namelist, event); 21594235b045SMasami Hiramatsu 21604235b045SMasami Hiramatsu /* Trick here - save current event/group */ 21614235b045SMasami Hiramatsu event = pev->event; 21624235b045SMasami Hiramatsu group = pev->group; 21634235b045SMasami Hiramatsu pev->event = tev->event; 21644235b045SMasami Hiramatsu pev->group = tev->group; 2165fb226ccdSMasami Hiramatsu show_perf_probe_event(pev, tev->point.module); 21664235b045SMasami Hiramatsu /* Trick here - restore current event/group */ 21674235b045SMasami Hiramatsu pev->event = (char *)event; 21684235b045SMasami Hiramatsu pev->group = (char *)group; 21694235b045SMasami Hiramatsu 2170d761b08bSMasami Hiramatsu /* 2171d761b08bSMasami Hiramatsu * Probes after the first probe which comes from same 2172d761b08bSMasami Hiramatsu * user input are always allowed to add suffix, because 2173d761b08bSMasami Hiramatsu * there might be several addresses corresponding to 2174d761b08bSMasami Hiramatsu * one code line. 2175d761b08bSMasami Hiramatsu */ 2176d761b08bSMasami Hiramatsu allow_suffix = true; 217750656eecSMasami Hiramatsu } 2178146a1439SMasami Hiramatsu 2179146a1439SMasami Hiramatsu if (ret >= 0) { 2180a9b495b0SMasami Hiramatsu /* Show how to use the event. */ 2181a844d1efSSrikar Dronamraju printf("\nYou can now use it in all perf tools, such as:\n\n"); 2182146a1439SMasami Hiramatsu printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, 2183146a1439SMasami Hiramatsu tev->event); 2184146a1439SMasami Hiramatsu } 2185a9b495b0SMasami Hiramatsu 2186e1d2017bSMasami Hiramatsu strlist__delete(namelist); 218750656eecSMasami Hiramatsu close(fd); 2188146a1439SMasami Hiramatsu return ret; 218950656eecSMasami Hiramatsu } 2190fa28244dSMasami Hiramatsu 2191eb948e50SMasami Hiramatsu static char *looking_function_name; 2192eb948e50SMasami Hiramatsu static int num_matched_functions; 2193eb948e50SMasami Hiramatsu 2194eb948e50SMasami Hiramatsu static int probe_function_filter(struct map *map __maybe_unused, 2195eb948e50SMasami Hiramatsu struct symbol *sym) 2196eb948e50SMasami Hiramatsu { 2197eb948e50SMasami Hiramatsu if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) && 2198eb948e50SMasami Hiramatsu strcmp(looking_function_name, sym->name) == 0) { 2199eb948e50SMasami Hiramatsu num_matched_functions++; 2200eb948e50SMasami Hiramatsu return 0; 2201eb948e50SMasami Hiramatsu } 2202eb948e50SMasami Hiramatsu return 1; 2203eb948e50SMasami Hiramatsu } 2204eb948e50SMasami Hiramatsu 2205eb948e50SMasami Hiramatsu #define strdup_or_goto(str, label) \ 2206eb948e50SMasami Hiramatsu ({ char *__p = strdup(str); if (!__p) goto label; __p; }) 2207eb948e50SMasami Hiramatsu 2208eb948e50SMasami Hiramatsu /* 2209eb948e50SMasami Hiramatsu * Find probe function addresses from map. 2210eb948e50SMasami Hiramatsu * Return an error or the number of found probe_trace_event 2211eb948e50SMasami Hiramatsu */ 2212eb948e50SMasami Hiramatsu static int find_probe_trace_events_from_map(struct perf_probe_event *pev, 2213eb948e50SMasami Hiramatsu struct probe_trace_event **tevs, 2214eb948e50SMasami Hiramatsu int max_tevs, const char *target) 2215eb948e50SMasami Hiramatsu { 2216eb948e50SMasami Hiramatsu struct map *map = NULL; 2217eb948e50SMasami Hiramatsu struct kmap *kmap = NULL; 2218eb948e50SMasami Hiramatsu struct ref_reloc_sym *reloc_sym = NULL; 2219eb948e50SMasami Hiramatsu struct symbol *sym; 2220eb948e50SMasami Hiramatsu struct rb_node *nd; 2221eb948e50SMasami Hiramatsu struct probe_trace_event *tev; 2222eb948e50SMasami Hiramatsu struct perf_probe_point *pp = &pev->point; 2223eb948e50SMasami Hiramatsu struct probe_trace_point *tp; 2224eb948e50SMasami Hiramatsu int ret, i; 2225eb948e50SMasami Hiramatsu 2226eb948e50SMasami Hiramatsu /* Init maps of given executable or kernel */ 2227eb948e50SMasami Hiramatsu if (pev->uprobes) 2228eb948e50SMasami Hiramatsu map = dso__new_map(target); 2229eb948e50SMasami Hiramatsu else 2230eb948e50SMasami Hiramatsu map = kernel_get_module_map(target); 2231eb948e50SMasami Hiramatsu if (!map) { 2232eb948e50SMasami Hiramatsu ret = -EINVAL; 2233eb948e50SMasami Hiramatsu goto out; 2234eb948e50SMasami Hiramatsu } 2235eb948e50SMasami Hiramatsu 2236eb948e50SMasami Hiramatsu /* 2237eb948e50SMasami Hiramatsu * Load matched symbols: Since the different local symbols may have 2238eb948e50SMasami Hiramatsu * same name but different addresses, this lists all the symbols. 2239eb948e50SMasami Hiramatsu */ 2240eb948e50SMasami Hiramatsu num_matched_functions = 0; 2241eb948e50SMasami Hiramatsu looking_function_name = pp->function; 2242eb948e50SMasami Hiramatsu ret = map__load(map, probe_function_filter); 2243eb948e50SMasami Hiramatsu if (ret || num_matched_functions == 0) { 2244eb948e50SMasami Hiramatsu pr_err("Failed to find symbol %s in %s\n", pp->function, 2245eb948e50SMasami Hiramatsu target ? : "kernel"); 2246eb948e50SMasami Hiramatsu ret = -ENOENT; 2247eb948e50SMasami Hiramatsu goto out; 2248eb948e50SMasami Hiramatsu } else if (num_matched_functions > max_tevs) { 2249eb948e50SMasami Hiramatsu pr_err("Too many functions matched in %s\n", 2250eb948e50SMasami Hiramatsu target ? : "kernel"); 2251eb948e50SMasami Hiramatsu ret = -E2BIG; 2252eb948e50SMasami Hiramatsu goto out; 2253eb948e50SMasami Hiramatsu } 2254eb948e50SMasami Hiramatsu 2255eb948e50SMasami Hiramatsu if (!pev->uprobes) { 2256eb948e50SMasami Hiramatsu kmap = map__kmap(map); 2257eb948e50SMasami Hiramatsu reloc_sym = kmap->ref_reloc_sym; 2258eb948e50SMasami Hiramatsu if (!reloc_sym) { 2259eb948e50SMasami Hiramatsu pr_warning("Relocated base symbol is not found!\n"); 2260eb948e50SMasami Hiramatsu ret = -EINVAL; 2261eb948e50SMasami Hiramatsu goto out; 2262eb948e50SMasami Hiramatsu } 2263eb948e50SMasami Hiramatsu } 2264eb948e50SMasami Hiramatsu 2265eb948e50SMasami Hiramatsu /* Setup result trace-probe-events */ 2266eb948e50SMasami Hiramatsu *tevs = zalloc(sizeof(*tev) * num_matched_functions); 2267eb948e50SMasami Hiramatsu if (!*tevs) { 2268eb948e50SMasami Hiramatsu ret = -ENOMEM; 2269eb948e50SMasami Hiramatsu goto out; 2270eb948e50SMasami Hiramatsu } 2271eb948e50SMasami Hiramatsu 2272eb948e50SMasami Hiramatsu ret = 0; 2273eb948e50SMasami Hiramatsu map__for_each_symbol(map, sym, nd) { 2274eb948e50SMasami Hiramatsu tev = (*tevs) + ret; 2275eb948e50SMasami Hiramatsu tp = &tev->point; 2276eb948e50SMasami Hiramatsu if (ret == num_matched_functions) { 2277eb948e50SMasami Hiramatsu pr_warning("Too many symbols are listed. Skip it.\n"); 2278eb948e50SMasami Hiramatsu break; 2279eb948e50SMasami Hiramatsu } 2280eb948e50SMasami Hiramatsu ret++; 2281eb948e50SMasami Hiramatsu 2282eb948e50SMasami Hiramatsu if (pp->offset > sym->end - sym->start) { 2283eb948e50SMasami Hiramatsu pr_warning("Offset %ld is bigger than the size of %s\n", 2284eb948e50SMasami Hiramatsu pp->offset, sym->name); 2285eb948e50SMasami Hiramatsu ret = -ENOENT; 2286eb948e50SMasami Hiramatsu goto err_out; 2287eb948e50SMasami Hiramatsu } 2288eb948e50SMasami Hiramatsu /* Add one probe point */ 2289eb948e50SMasami Hiramatsu tp->address = map->unmap_ip(map, sym->start) + pp->offset; 2290eb948e50SMasami Hiramatsu if (reloc_sym) { 2291eb948e50SMasami Hiramatsu tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out); 2292eb948e50SMasami Hiramatsu tp->offset = tp->address - reloc_sym->addr; 2293eb948e50SMasami Hiramatsu } else { 2294eb948e50SMasami Hiramatsu tp->symbol = strdup_or_goto(sym->name, nomem_out); 2295eb948e50SMasami Hiramatsu tp->offset = pp->offset; 2296eb948e50SMasami Hiramatsu } 2297eb948e50SMasami Hiramatsu tp->retprobe = pp->retprobe; 2298eb948e50SMasami Hiramatsu if (target) 2299eb948e50SMasami Hiramatsu tev->point.module = strdup_or_goto(target, nomem_out); 2300eb948e50SMasami Hiramatsu tev->uprobes = pev->uprobes; 2301eb948e50SMasami Hiramatsu tev->nargs = pev->nargs; 2302eb948e50SMasami Hiramatsu if (tev->nargs) { 2303eb948e50SMasami Hiramatsu tev->args = zalloc(sizeof(struct probe_trace_arg) * 2304eb948e50SMasami Hiramatsu tev->nargs); 2305eb948e50SMasami Hiramatsu if (tev->args == NULL) 2306eb948e50SMasami Hiramatsu goto nomem_out; 2307eb948e50SMasami Hiramatsu } 2308eb948e50SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 2309eb948e50SMasami Hiramatsu if (pev->args[i].name) 2310eb948e50SMasami Hiramatsu tev->args[i].name = 2311eb948e50SMasami Hiramatsu strdup_or_goto(pev->args[i].name, 2312eb948e50SMasami Hiramatsu nomem_out); 2313eb948e50SMasami Hiramatsu 2314eb948e50SMasami Hiramatsu tev->args[i].value = strdup_or_goto(pev->args[i].var, 2315eb948e50SMasami Hiramatsu nomem_out); 2316eb948e50SMasami Hiramatsu if (pev->args[i].type) 2317eb948e50SMasami Hiramatsu tev->args[i].type = 2318eb948e50SMasami Hiramatsu strdup_or_goto(pev->args[i].type, 2319eb948e50SMasami Hiramatsu nomem_out); 2320eb948e50SMasami Hiramatsu } 2321eb948e50SMasami Hiramatsu } 2322eb948e50SMasami Hiramatsu 2323eb948e50SMasami Hiramatsu out: 2324eb948e50SMasami Hiramatsu if (map && pev->uprobes) { 2325eb948e50SMasami Hiramatsu /* Only when using uprobe(exec) map needs to be released */ 2326eb948e50SMasami Hiramatsu dso__delete(map->dso); 2327eb948e50SMasami Hiramatsu map__delete(map); 2328eb948e50SMasami Hiramatsu } 2329eb948e50SMasami Hiramatsu return ret; 2330eb948e50SMasami Hiramatsu 2331eb948e50SMasami Hiramatsu nomem_out: 2332eb948e50SMasami Hiramatsu ret = -ENOMEM; 2333eb948e50SMasami Hiramatsu err_out: 2334eb948e50SMasami Hiramatsu clear_probe_trace_events(*tevs, num_matched_functions); 2335eb948e50SMasami Hiramatsu zfree(tevs); 2336eb948e50SMasami Hiramatsu goto out; 2337eb948e50SMasami Hiramatsu } 2338eb948e50SMasami Hiramatsu 23390e60836bSSrikar Dronamraju static int convert_to_probe_trace_events(struct perf_probe_event *pev, 23400e60836bSSrikar Dronamraju struct probe_trace_event **tevs, 23414eced234SSrikar Dronamraju int max_tevs, const char *target) 2342e0faa8d3SMasami Hiramatsu { 2343eb948e50SMasami Hiramatsu int ret; 23444235b045SMasami Hiramatsu 2345fb7345bbSMasami Hiramatsu if (pev->uprobes && !pev->group) { 2346fb7345bbSMasami Hiramatsu /* Replace group name if not given */ 2347fb7345bbSMasami Hiramatsu ret = convert_exec_to_group(target, &pev->group); 2348fb7345bbSMasami Hiramatsu if (ret != 0) { 2349fb7345bbSMasami Hiramatsu pr_warning("Failed to make a group name.\n"); 2350fb7345bbSMasami Hiramatsu return ret; 2351fb7345bbSMasami Hiramatsu } 2352fb7345bbSMasami Hiramatsu } 2353fb7345bbSMasami Hiramatsu 23544b4da7f7SMasami Hiramatsu /* Convert perf_probe_event with debuginfo */ 23554eced234SSrikar Dronamraju ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); 2356e334016fSMasami Hiramatsu if (ret != 0) 2357190b57fcSMasami Hiramatsu return ret; /* Found in debuginfo or got an error */ 2358e0faa8d3SMasami Hiramatsu 2359eb948e50SMasami Hiramatsu return find_probe_trace_events_from_map(pev, tevs, max_tevs, target); 23604235b045SMasami Hiramatsu } 23614235b045SMasami Hiramatsu 23624235b045SMasami Hiramatsu struct __event_package { 23634235b045SMasami Hiramatsu struct perf_probe_event *pev; 23640e60836bSSrikar Dronamraju struct probe_trace_event *tevs; 23654235b045SMasami Hiramatsu int ntevs; 23664235b045SMasami Hiramatsu }; 23674235b045SMasami Hiramatsu 2368146a1439SMasami Hiramatsu int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 23694eced234SSrikar Dronamraju int max_tevs, const char *target, bool force_add) 23704235b045SMasami Hiramatsu { 2371146a1439SMasami Hiramatsu int i, j, ret; 23724235b045SMasami Hiramatsu struct __event_package *pkgs; 23734235b045SMasami Hiramatsu 2374225466f1SSrikar Dronamraju ret = 0; 2375e334016fSMasami Hiramatsu pkgs = zalloc(sizeof(struct __event_package) * npevs); 2376225466f1SSrikar Dronamraju 2377e334016fSMasami Hiramatsu if (pkgs == NULL) 2378e334016fSMasami Hiramatsu return -ENOMEM; 23794235b045SMasami Hiramatsu 2380ee45b6c2SMasami Hiramatsu ret = init_symbol_maps(pevs->uprobes); 2381449e5b24SMasami Hiramatsu if (ret < 0) { 2382449e5b24SMasami Hiramatsu free(pkgs); 2383146a1439SMasami Hiramatsu return ret; 2384449e5b24SMasami Hiramatsu } 23854235b045SMasami Hiramatsu 23864235b045SMasami Hiramatsu /* Loop 1: convert all events */ 23874235b045SMasami Hiramatsu for (i = 0; i < npevs; i++) { 23884235b045SMasami Hiramatsu pkgs[i].pev = &pevs[i]; 23894235b045SMasami Hiramatsu /* Convert with or without debuginfo */ 23900e60836bSSrikar Dronamraju ret = convert_to_probe_trace_events(pkgs[i].pev, 2391469b9b88SMasami Hiramatsu &pkgs[i].tevs, 2392469b9b88SMasami Hiramatsu max_tevs, 23934eced234SSrikar Dronamraju target); 2394146a1439SMasami Hiramatsu if (ret < 0) 2395146a1439SMasami Hiramatsu goto end; 2396146a1439SMasami Hiramatsu pkgs[i].ntevs = ret; 23974235b045SMasami Hiramatsu } 23984235b045SMasami Hiramatsu 23994235b045SMasami Hiramatsu /* Loop 2: add all events */ 24008635bf6eSArnaldo Carvalho de Melo for (i = 0; i < npevs; i++) { 24010e60836bSSrikar Dronamraju ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, 24024235b045SMasami Hiramatsu pkgs[i].ntevs, force_add); 2403fbee632dSArnaldo Carvalho de Melo if (ret < 0) 2404fbee632dSArnaldo Carvalho de Melo break; 2405fbee632dSArnaldo Carvalho de Melo } 2406146a1439SMasami Hiramatsu end: 2407449e5b24SMasami Hiramatsu /* Loop 3: cleanup and free trace events */ 2408449e5b24SMasami Hiramatsu for (i = 0; i < npevs; i++) { 2409146a1439SMasami Hiramatsu for (j = 0; j < pkgs[i].ntevs; j++) 24100e60836bSSrikar Dronamraju clear_probe_trace_event(&pkgs[i].tevs[j]); 241174cf249dSArnaldo Carvalho de Melo zfree(&pkgs[i].tevs); 2412449e5b24SMasami Hiramatsu } 2413449e5b24SMasami Hiramatsu free(pkgs); 2414ee45b6c2SMasami Hiramatsu exit_symbol_maps(); 2415146a1439SMasami Hiramatsu 2416146a1439SMasami Hiramatsu return ret; 2417e0faa8d3SMasami Hiramatsu } 2418e0faa8d3SMasami Hiramatsu 24190e60836bSSrikar Dronamraju static int __del_trace_probe_event(int fd, struct str_node *ent) 2420bbbb521bSMasami Hiramatsu { 2421bbbb521bSMasami Hiramatsu char *p; 2422bbbb521bSMasami Hiramatsu char buf[128]; 24234235b045SMasami Hiramatsu int ret; 2424bbbb521bSMasami Hiramatsu 24250e60836bSSrikar Dronamraju /* Convert from perf-probe event to trace-probe event */ 2426146a1439SMasami Hiramatsu ret = e_snprintf(buf, 128, "-:%s", ent->s); 2427146a1439SMasami Hiramatsu if (ret < 0) 2428146a1439SMasami Hiramatsu goto error; 2429146a1439SMasami Hiramatsu 2430bbbb521bSMasami Hiramatsu p = strchr(buf + 2, ':'); 2431146a1439SMasami Hiramatsu if (!p) { 2432146a1439SMasami Hiramatsu pr_debug("Internal error: %s should have ':' but not.\n", 2433146a1439SMasami Hiramatsu ent->s); 2434146a1439SMasami Hiramatsu ret = -ENOTSUP; 2435146a1439SMasami Hiramatsu goto error; 2436146a1439SMasami Hiramatsu } 2437bbbb521bSMasami Hiramatsu *p = '/'; 2438bbbb521bSMasami Hiramatsu 24394235b045SMasami Hiramatsu pr_debug("Writing event: %s\n", buf); 24404235b045SMasami Hiramatsu ret = write(fd, buf, strlen(buf)); 244144a56040SMasami Hiramatsu if (ret < 0) { 244244a56040SMasami Hiramatsu ret = -errno; 2443146a1439SMasami Hiramatsu goto error; 244444a56040SMasami Hiramatsu } 2445146a1439SMasami Hiramatsu 2446a844d1efSSrikar Dronamraju printf("Removed event: %s\n", ent->s); 2447146a1439SMasami Hiramatsu return 0; 2448146a1439SMasami Hiramatsu error: 24495f03cba4SMasami Hiramatsu pr_warning("Failed to delete event: %s\n", 24505f03cba4SMasami Hiramatsu strerror_r(-ret, buf, sizeof(buf))); 2451146a1439SMasami Hiramatsu return ret; 2452bbbb521bSMasami Hiramatsu } 2453bbbb521bSMasami Hiramatsu 2454225466f1SSrikar Dronamraju static int del_trace_probe_event(int fd, const char *buf, 2455225466f1SSrikar Dronamraju struct strlist *namelist) 2456fa28244dSMasami Hiramatsu { 2457bbbb521bSMasami Hiramatsu struct str_node *ent, *n; 2458225466f1SSrikar Dronamraju int ret = -1; 2459fa28244dSMasami Hiramatsu 2460bbbb521bSMasami Hiramatsu if (strpbrk(buf, "*?")) { /* Glob-exp */ 2461bbbb521bSMasami Hiramatsu strlist__for_each_safe(ent, n, namelist) 2462bbbb521bSMasami Hiramatsu if (strglobmatch(ent->s, buf)) { 24630e60836bSSrikar Dronamraju ret = __del_trace_probe_event(fd, ent); 2464146a1439SMasami Hiramatsu if (ret < 0) 2465146a1439SMasami Hiramatsu break; 24663e340590SMasami Hiramatsu strlist__remove(namelist, ent); 2467fa28244dSMasami Hiramatsu } 2468bbbb521bSMasami Hiramatsu } else { 2469bbbb521bSMasami Hiramatsu ent = strlist__find(namelist, buf); 2470bbbb521bSMasami Hiramatsu if (ent) { 24710e60836bSSrikar Dronamraju ret = __del_trace_probe_event(fd, ent); 2472146a1439SMasami Hiramatsu if (ret >= 0) 2473bbbb521bSMasami Hiramatsu strlist__remove(namelist, ent); 2474bbbb521bSMasami Hiramatsu } 2475bbbb521bSMasami Hiramatsu } 2476146a1439SMasami Hiramatsu 2477146a1439SMasami Hiramatsu return ret; 2478bbbb521bSMasami Hiramatsu } 2479fa28244dSMasami Hiramatsu 2480146a1439SMasami Hiramatsu int del_perf_probe_events(struct strlist *dellist) 2481fa28244dSMasami Hiramatsu { 2482225466f1SSrikar Dronamraju int ret = -1, ufd = -1, kfd = -1; 2483225466f1SSrikar Dronamraju char buf[128]; 2484fa28244dSMasami Hiramatsu const char *group, *event; 2485fa28244dSMasami Hiramatsu char *p, *str; 2486fa28244dSMasami Hiramatsu struct str_node *ent; 2487225466f1SSrikar Dronamraju struct strlist *namelist = NULL, *unamelist = NULL; 2488146a1439SMasami Hiramatsu 2489fa28244dSMasami Hiramatsu /* Get current event names */ 2490225466f1SSrikar Dronamraju kfd = open_kprobe_events(true); 2491467ec085SMasami Hiramatsu if (kfd >= 0) 2492225466f1SSrikar Dronamraju namelist = get_probe_trace_event_names(kfd, true); 2493225466f1SSrikar Dronamraju 2494467ec085SMasami Hiramatsu ufd = open_uprobe_events(true); 2495467ec085SMasami Hiramatsu if (ufd >= 0) 2496225466f1SSrikar Dronamraju unamelist = get_probe_trace_event_names(ufd, true); 2497225466f1SSrikar Dronamraju 2498467ec085SMasami Hiramatsu if (kfd < 0 && ufd < 0) { 2499467ec085SMasami Hiramatsu print_both_open_warning(kfd, ufd); 2500467ec085SMasami Hiramatsu goto error; 2501467ec085SMasami Hiramatsu } 2502467ec085SMasami Hiramatsu 2503225466f1SSrikar Dronamraju if (namelist == NULL && unamelist == NULL) 2504225466f1SSrikar Dronamraju goto error; 2505fa28244dSMasami Hiramatsu 2506adf365f4SMasami Hiramatsu strlist__for_each(ent, dellist) { 250702b95dadSMasami Hiramatsu str = strdup(ent->s); 250802b95dadSMasami Hiramatsu if (str == NULL) { 250902b95dadSMasami Hiramatsu ret = -ENOMEM; 2510225466f1SSrikar Dronamraju goto error; 251102b95dadSMasami Hiramatsu } 2512bbbb521bSMasami Hiramatsu pr_debug("Parsing: %s\n", str); 2513fa28244dSMasami Hiramatsu p = strchr(str, ':'); 2514fa28244dSMasami Hiramatsu if (p) { 2515fa28244dSMasami Hiramatsu group = str; 2516fa28244dSMasami Hiramatsu *p = '\0'; 2517fa28244dSMasami Hiramatsu event = p + 1; 2518fa28244dSMasami Hiramatsu } else { 2519bbbb521bSMasami Hiramatsu group = "*"; 2520fa28244dSMasami Hiramatsu event = str; 2521fa28244dSMasami Hiramatsu } 2522225466f1SSrikar Dronamraju 2523225466f1SSrikar Dronamraju ret = e_snprintf(buf, 128, "%s:%s", group, event); 2524225466f1SSrikar Dronamraju if (ret < 0) { 2525225466f1SSrikar Dronamraju pr_err("Failed to copy event."); 2526fa28244dSMasami Hiramatsu free(str); 2527225466f1SSrikar Dronamraju goto error; 2528fa28244dSMasami Hiramatsu } 2529225466f1SSrikar Dronamraju 2530225466f1SSrikar Dronamraju pr_debug("Group: %s, Event: %s\n", group, event); 2531225466f1SSrikar Dronamraju 2532225466f1SSrikar Dronamraju if (namelist) 2533225466f1SSrikar Dronamraju ret = del_trace_probe_event(kfd, buf, namelist); 2534225466f1SSrikar Dronamraju 2535225466f1SSrikar Dronamraju if (unamelist && ret != 0) 2536225466f1SSrikar Dronamraju ret = del_trace_probe_event(ufd, buf, unamelist); 2537225466f1SSrikar Dronamraju 2538225466f1SSrikar Dronamraju if (ret != 0) 2539225466f1SSrikar Dronamraju pr_info("Info: Event \"%s\" does not exist.\n", buf); 2540225466f1SSrikar Dronamraju 2541225466f1SSrikar Dronamraju free(str); 2542225466f1SSrikar Dronamraju } 2543225466f1SSrikar Dronamraju 2544225466f1SSrikar Dronamraju error: 2545225466f1SSrikar Dronamraju if (kfd >= 0) { 2546fa28244dSMasami Hiramatsu strlist__delete(namelist); 2547225466f1SSrikar Dronamraju close(kfd); 2548225466f1SSrikar Dronamraju } 2549225466f1SSrikar Dronamraju 2550225466f1SSrikar Dronamraju if (ufd >= 0) { 2551225466f1SSrikar Dronamraju strlist__delete(unamelist); 2552225466f1SSrikar Dronamraju close(ufd); 2553225466f1SSrikar Dronamraju } 2554146a1439SMasami Hiramatsu 2555146a1439SMasami Hiramatsu return ret; 2556fa28244dSMasami Hiramatsu } 2557225466f1SSrikar Dronamraju 25583c42258cSMasami Hiramatsu /* TODO: don't use a global variable for filter ... */ 25593c42258cSMasami Hiramatsu static struct strfilter *available_func_filter; 2560fa28244dSMasami Hiramatsu 2561e80711caSMasami Hiramatsu /* 25623c42258cSMasami Hiramatsu * If a symbol corresponds to a function with global binding and 25633c42258cSMasami Hiramatsu * matches filter return 0. For all others return 1. 2564e80711caSMasami Hiramatsu */ 25651d037ca1SIrina Tirdea static int filter_available_functions(struct map *map __maybe_unused, 2566e80711caSMasami Hiramatsu struct symbol *sym) 2567e80711caSMasami Hiramatsu { 2568eb948e50SMasami Hiramatsu if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) && 25693c42258cSMasami Hiramatsu strfilter__compare(available_func_filter, sym->name)) 2570e80711caSMasami Hiramatsu return 0; 25713c42258cSMasami Hiramatsu return 1; 2572e80711caSMasami Hiramatsu } 2573e80711caSMasami Hiramatsu 25742df58634SMasami Hiramatsu int show_available_funcs(const char *target, struct strfilter *_filter, 25752df58634SMasami Hiramatsu bool user) 2576e80711caSMasami Hiramatsu { 25772df58634SMasami Hiramatsu struct map *map; 25782df58634SMasami Hiramatsu int ret; 25792df58634SMasami Hiramatsu 25802df58634SMasami Hiramatsu ret = init_symbol_maps(user); 25812df58634SMasami Hiramatsu if (ret < 0) 25822df58634SMasami Hiramatsu return ret; 25832df58634SMasami Hiramatsu 25842df58634SMasami Hiramatsu /* Get a symbol map */ 25852df58634SMasami Hiramatsu if (user) 25862df58634SMasami Hiramatsu map = dso__new_map(target); 25872df58634SMasami Hiramatsu else 25882df58634SMasami Hiramatsu map = kernel_get_module_map(target); 25892df58634SMasami Hiramatsu if (!map) { 25902df58634SMasami Hiramatsu pr_err("Failed to get a map for %s\n", (target) ? : "kernel"); 2591e80711caSMasami Hiramatsu return -EINVAL; 2592e80711caSMasami Hiramatsu } 25932df58634SMasami Hiramatsu 25942df58634SMasami Hiramatsu /* Load symbols with given filter */ 25952df58634SMasami Hiramatsu available_func_filter = _filter; 25962df58634SMasami Hiramatsu if (map__load(map, filter_available_functions)) { 25972df58634SMasami Hiramatsu pr_err("Failed to load symbols in %s\n", (target) ? : "kernel"); 25982df58634SMasami Hiramatsu goto end; 25992df58634SMasami Hiramatsu } 2600e80711caSMasami Hiramatsu if (!dso__sorted_by_name(map->dso, map->type)) 2601e80711caSMasami Hiramatsu dso__sort_by_name(map->dso, map->type); 2602e80711caSMasami Hiramatsu 26032df58634SMasami Hiramatsu /* Show all (filtered) symbols */ 26042df58634SMasami Hiramatsu setup_pager(); 2605e80711caSMasami Hiramatsu dso__fprintf_symbols_by_name(map->dso, map->type, stdout); 26062df58634SMasami Hiramatsu end: 26072df58634SMasami Hiramatsu if (user) { 2608225466f1SSrikar Dronamraju dso__delete(map->dso); 2609225466f1SSrikar Dronamraju map__delete(map); 2610225466f1SSrikar Dronamraju } 26112df58634SMasami Hiramatsu exit_symbol_maps(); 2612225466f1SSrikar Dronamraju 26132df58634SMasami Hiramatsu return ret; 2614225466f1SSrikar Dronamraju } 2615225466f1SSrikar Dronamraju 2616