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" 37e1c01d61SMasami Hiramatsu #include "string.h" 384de189feSMasami Hiramatsu #include "strlist.h" 3950656eecSMasami Hiramatsu #include "debug.h" 4072041334SMasami Hiramatsu #include "cache.h" 41631c9defSMasami Hiramatsu #include "color.h" 42e0faa8d3SMasami Hiramatsu #include "symbol.h" 43e0faa8d3SMasami Hiramatsu #include "thread.h" 447ca5989dSMasami Hiramatsu #include "debugfs.h" 454b4da7f7SMasami Hiramatsu #include "trace-event.h" /* For __unused */ 4650656eecSMasami Hiramatsu #include "probe-event.h" 474235b045SMasami Hiramatsu #include "probe-finder.h" 4850656eecSMasami Hiramatsu 4950656eecSMasami Hiramatsu #define MAX_CMDLEN 256 5050656eecSMasami Hiramatsu #define MAX_PROBE_ARGS 128 5150656eecSMasami Hiramatsu #define PERFPROBE_GROUP "probe" 5250656eecSMasami Hiramatsu 53f4d7da49SMasami Hiramatsu bool probe_event_dry_run; /* Dry run flag */ 54f4d7da49SMasami Hiramatsu 55146a1439SMasami Hiramatsu #define semantic_error(msg ...) pr_err("Semantic error :" msg) 5650656eecSMasami Hiramatsu 574de189feSMasami Hiramatsu /* If there is no space to write, returns -E2BIG. */ 584de189feSMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...) 5984988450SMasami Hiramatsu __attribute__((format(printf, 3, 4))); 6084988450SMasami Hiramatsu 6184988450SMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...) 624de189feSMasami Hiramatsu { 634de189feSMasami Hiramatsu int ret; 644de189feSMasami Hiramatsu va_list ap; 654de189feSMasami Hiramatsu va_start(ap, format); 664de189feSMasami Hiramatsu ret = vsnprintf(str, size, format, ap); 674de189feSMasami Hiramatsu va_end(ap); 684de189feSMasami Hiramatsu if (ret >= (int)size) 694de189feSMasami Hiramatsu ret = -E2BIG; 704de189feSMasami Hiramatsu return ret; 714de189feSMasami Hiramatsu } 724de189feSMasami Hiramatsu 734b4da7f7SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 74d28c6223SArnaldo Carvalho de Melo static struct machine machine; 75e0faa8d3SMasami Hiramatsu 76469b9b88SMasami Hiramatsu /* Initialize symbol maps and path of vmlinux/modules */ 77146a1439SMasami Hiramatsu static int init_vmlinux(void) 78e0faa8d3SMasami Hiramatsu { 79146a1439SMasami Hiramatsu int ret; 80146a1439SMasami Hiramatsu 81e0faa8d3SMasami Hiramatsu symbol_conf.sort_by_name = true; 82e0faa8d3SMasami Hiramatsu if (symbol_conf.vmlinux_name == NULL) 83e0faa8d3SMasami Hiramatsu symbol_conf.try_vmlinux_path = true; 84e0faa8d3SMasami Hiramatsu else 85e0faa8d3SMasami Hiramatsu pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name); 86146a1439SMasami Hiramatsu ret = symbol__init(); 87146a1439SMasami Hiramatsu if (ret < 0) { 88146a1439SMasami Hiramatsu pr_debug("Failed to init symbol map.\n"); 89146a1439SMasami Hiramatsu goto out; 90146a1439SMasami Hiramatsu } 91e0faa8d3SMasami Hiramatsu 92469b9b88SMasami Hiramatsu ret = machine__init(&machine, "", HOST_KERNEL_ID); 93d28c6223SArnaldo Carvalho de Melo if (ret < 0) 94d28c6223SArnaldo Carvalho de Melo goto out; 95d28c6223SArnaldo Carvalho de Melo 96469b9b88SMasami Hiramatsu if (machine__create_kernel_maps(&machine) < 0) { 970e43e5d2SMasami Hiramatsu pr_debug("machine__create_kernel_maps() failed.\n"); 98469b9b88SMasami Hiramatsu goto out; 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 106469b9b88SMasami Hiramatsu static struct symbol *__find_kernel_function_by_name(const char *name, 107469b9b88SMasami Hiramatsu struct map **mapp) 108e0faa8d3SMasami Hiramatsu { 109469b9b88SMasami Hiramatsu return machine__find_kernel_function_by_name(&machine, name, mapp, 110469b9b88SMasami Hiramatsu NULL); 111e0faa8d3SMasami Hiramatsu } 112469b9b88SMasami Hiramatsu 113e80711caSMasami Hiramatsu static struct map *kernel_get_module_map(const char *module) 114e80711caSMasami Hiramatsu { 115e80711caSMasami Hiramatsu struct rb_node *nd; 116e80711caSMasami Hiramatsu struct map_groups *grp = &machine.kmaps; 117e80711caSMasami Hiramatsu 11814a8fd7cSMasami Hiramatsu /* A file path -- this is an offline module */ 11914a8fd7cSMasami Hiramatsu if (module && strchr(module, '/')) 12014a8fd7cSMasami Hiramatsu return machine__new_module(&machine, 0, module); 12114a8fd7cSMasami Hiramatsu 122e80711caSMasami Hiramatsu if (!module) 123e80711caSMasami Hiramatsu module = "kernel"; 124e80711caSMasami Hiramatsu 125e80711caSMasami Hiramatsu for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { 126e80711caSMasami Hiramatsu struct map *pos = rb_entry(nd, struct map, rb_node); 127e80711caSMasami Hiramatsu if (strncmp(pos->dso->short_name + 1, module, 128e80711caSMasami Hiramatsu pos->dso->short_name_len - 2) == 0) { 129e80711caSMasami Hiramatsu return pos; 130e80711caSMasami Hiramatsu } 131e80711caSMasami Hiramatsu } 132e80711caSMasami Hiramatsu return NULL; 133e80711caSMasami Hiramatsu } 134e80711caSMasami Hiramatsu 135e80711caSMasami Hiramatsu static struct dso *kernel_get_module_dso(const char *module) 136469b9b88SMasami Hiramatsu { 137469b9b88SMasami Hiramatsu struct dso *dso; 138fd930ff9SFranck Bui-Huu struct map *map; 139fd930ff9SFranck Bui-Huu const char *vmlinux_name; 140469b9b88SMasami Hiramatsu 141469b9b88SMasami Hiramatsu if (module) { 142469b9b88SMasami Hiramatsu list_for_each_entry(dso, &machine.kernel_dsos, node) { 143469b9b88SMasami Hiramatsu if (strncmp(dso->short_name + 1, module, 144469b9b88SMasami Hiramatsu dso->short_name_len - 2) == 0) 145469b9b88SMasami Hiramatsu goto found; 146469b9b88SMasami Hiramatsu } 147469b9b88SMasami Hiramatsu pr_debug("Failed to find module %s.\n", module); 148469b9b88SMasami Hiramatsu return NULL; 149fd930ff9SFranck Bui-Huu } 150fd930ff9SFranck Bui-Huu 151fd930ff9SFranck Bui-Huu map = machine.vmlinux_maps[MAP__FUNCTION]; 152fd930ff9SFranck Bui-Huu dso = map->dso; 153fd930ff9SFranck Bui-Huu 154fd930ff9SFranck Bui-Huu vmlinux_name = symbol_conf.vmlinux_name; 155fd930ff9SFranck Bui-Huu if (vmlinux_name) { 156fd930ff9SFranck Bui-Huu if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0) 157fd930ff9SFranck Bui-Huu return NULL; 158469b9b88SMasami Hiramatsu } else { 159c3a34e06SFranck Bui-Huu if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { 160469b9b88SMasami Hiramatsu pr_debug("Failed to load kernel map.\n"); 161469b9b88SMasami Hiramatsu return NULL; 162469b9b88SMasami Hiramatsu } 163469b9b88SMasami Hiramatsu } 164469b9b88SMasami Hiramatsu found: 165e80711caSMasami Hiramatsu return dso; 166e80711caSMasami Hiramatsu } 167e80711caSMasami Hiramatsu 168e80711caSMasami Hiramatsu const char *kernel_get_module_path(const char *module) 169e80711caSMasami Hiramatsu { 170e80711caSMasami Hiramatsu struct dso *dso = kernel_get_module_dso(module); 171e80711caSMasami Hiramatsu return (dso) ? dso->long_name : NULL; 172469b9b88SMasami Hiramatsu } 173469b9b88SMasami Hiramatsu 174469b9b88SMasami Hiramatsu #ifdef DWARF_SUPPORT 175ff741783SMasami Hiramatsu /* Open new debuginfo of given module */ 176ff741783SMasami Hiramatsu static struct debuginfo *open_debuginfo(const char *module) 177469b9b88SMasami Hiramatsu { 17814a8fd7cSMasami Hiramatsu const char *path; 17914a8fd7cSMasami Hiramatsu 18014a8fd7cSMasami Hiramatsu /* A file path -- this is an offline module */ 18114a8fd7cSMasami Hiramatsu if (module && strchr(module, '/')) 18214a8fd7cSMasami Hiramatsu path = module; 18314a8fd7cSMasami Hiramatsu else { 18414a8fd7cSMasami Hiramatsu path = kernel_get_module_path(module); 185ff741783SMasami Hiramatsu 186469b9b88SMasami Hiramatsu if (!path) { 1870e43e5d2SMasami Hiramatsu pr_err("Failed to find path of %s module.\n", 1880e43e5d2SMasami Hiramatsu module ?: "kernel"); 189ff741783SMasami Hiramatsu return NULL; 190469b9b88SMasami Hiramatsu } 19114a8fd7cSMasami Hiramatsu } 192ff741783SMasami Hiramatsu return debuginfo__new(path); 193e0faa8d3SMasami Hiramatsu } 1944b4da7f7SMasami Hiramatsu 1950e60836bSSrikar Dronamraju /* 1960e60836bSSrikar Dronamraju * Convert trace point to probe point with debuginfo 1970e60836bSSrikar Dronamraju * Currently only handles kprobes. 1980e60836bSSrikar Dronamraju */ 1990e60836bSSrikar Dronamraju static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 2004b4da7f7SMasami Hiramatsu struct perf_probe_point *pp) 2014b4da7f7SMasami Hiramatsu { 2024b4da7f7SMasami Hiramatsu struct symbol *sym; 203469b9b88SMasami Hiramatsu struct map *map; 204469b9b88SMasami Hiramatsu u64 addr; 205469b9b88SMasami Hiramatsu int ret = -ENOENT; 206ff741783SMasami Hiramatsu struct debuginfo *dinfo; 2074b4da7f7SMasami Hiramatsu 208469b9b88SMasami Hiramatsu sym = __find_kernel_function_by_name(tp->symbol, &map); 2094b4da7f7SMasami Hiramatsu if (sym) { 210469b9b88SMasami Hiramatsu addr = map->unmap_ip(map, sym->start + tp->offset); 2119486aa38SArnaldo Carvalho de Melo pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol, 212469b9b88SMasami Hiramatsu tp->offset, addr); 213ff741783SMasami Hiramatsu 214ff741783SMasami Hiramatsu dinfo = debuginfo__new_online_kernel(addr); 215ff741783SMasami Hiramatsu if (dinfo) { 216ff741783SMasami Hiramatsu ret = debuginfo__find_probe_point(dinfo, 217ff741783SMasami Hiramatsu (unsigned long)addr, pp); 218ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 219ff741783SMasami Hiramatsu } else { 220ff741783SMasami Hiramatsu pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", 221ff741783SMasami Hiramatsu addr); 222ff741783SMasami Hiramatsu ret = -ENOENT; 223ff741783SMasami Hiramatsu } 224146a1439SMasami Hiramatsu } 2254b4da7f7SMasami Hiramatsu if (ret <= 0) { 226146a1439SMasami Hiramatsu pr_debug("Failed to find corresponding probes from " 227146a1439SMasami Hiramatsu "debuginfo. Use kprobe event information.\n"); 22802b95dadSMasami Hiramatsu pp->function = strdup(tp->symbol); 22902b95dadSMasami Hiramatsu if (pp->function == NULL) 23002b95dadSMasami Hiramatsu return -ENOMEM; 2314b4da7f7SMasami Hiramatsu pp->offset = tp->offset; 2324b4da7f7SMasami Hiramatsu } 2334b4da7f7SMasami Hiramatsu pp->retprobe = tp->retprobe; 234146a1439SMasami Hiramatsu 235146a1439SMasami Hiramatsu return 0; 2364b4da7f7SMasami Hiramatsu } 2374b4da7f7SMasami Hiramatsu 238190b57fcSMasami Hiramatsu static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, 239190b57fcSMasami Hiramatsu int ntevs, const char *module) 240190b57fcSMasami Hiramatsu { 24114a8fd7cSMasami Hiramatsu int i, ret = 0; 24214a8fd7cSMasami Hiramatsu char *tmp; 24314a8fd7cSMasami Hiramatsu 24414a8fd7cSMasami Hiramatsu if (!module) 24514a8fd7cSMasami Hiramatsu return 0; 24614a8fd7cSMasami Hiramatsu 24714a8fd7cSMasami Hiramatsu tmp = strrchr(module, '/'); 24814a8fd7cSMasami Hiramatsu if (tmp) { 24914a8fd7cSMasami Hiramatsu /* This is a module path -- get the module name */ 25014a8fd7cSMasami Hiramatsu module = strdup(tmp + 1); 25114a8fd7cSMasami Hiramatsu if (!module) 25214a8fd7cSMasami Hiramatsu return -ENOMEM; 25314a8fd7cSMasami Hiramatsu tmp = strchr(module, '.'); 25414a8fd7cSMasami Hiramatsu if (tmp) 25514a8fd7cSMasami Hiramatsu *tmp = '\0'; 25614a8fd7cSMasami Hiramatsu tmp = (char *)module; /* For free() */ 25714a8fd7cSMasami Hiramatsu } 25814a8fd7cSMasami Hiramatsu 259190b57fcSMasami Hiramatsu for (i = 0; i < ntevs; i++) { 260190b57fcSMasami Hiramatsu tevs[i].point.module = strdup(module); 26114a8fd7cSMasami Hiramatsu if (!tevs[i].point.module) { 26214a8fd7cSMasami Hiramatsu ret = -ENOMEM; 26314a8fd7cSMasami Hiramatsu break; 264190b57fcSMasami Hiramatsu } 26514a8fd7cSMasami Hiramatsu } 26614a8fd7cSMasami Hiramatsu 26714a8fd7cSMasami Hiramatsu if (tmp) 26814a8fd7cSMasami Hiramatsu free(tmp); 26914a8fd7cSMasami Hiramatsu 27014a8fd7cSMasami Hiramatsu return ret; 271190b57fcSMasami Hiramatsu } 272190b57fcSMasami Hiramatsu 2734b4da7f7SMasami Hiramatsu /* Try to find perf_probe_event with debuginfo */ 2740e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 2750e60836bSSrikar Dronamraju struct probe_trace_event **tevs, 276469b9b88SMasami Hiramatsu int max_tevs, const char *module) 2774b4da7f7SMasami Hiramatsu { 2784b4da7f7SMasami Hiramatsu bool need_dwarf = perf_probe_event_need_dwarf(pev); 279ff741783SMasami Hiramatsu struct debuginfo *dinfo = open_debuginfo(module); 280190b57fcSMasami Hiramatsu int ntevs, ret = 0; 2814b4da7f7SMasami Hiramatsu 282ff741783SMasami Hiramatsu if (!dinfo) { 283146a1439SMasami Hiramatsu if (need_dwarf) { 284146a1439SMasami Hiramatsu pr_warning("Failed to open debuginfo file.\n"); 285ff741783SMasami Hiramatsu return -ENOENT; 286146a1439SMasami Hiramatsu } 287ff741783SMasami Hiramatsu pr_debug("Could not open debuginfo. Try to use symbols.\n"); 2884b4da7f7SMasami Hiramatsu return 0; 2894b4da7f7SMasami Hiramatsu } 2904b4da7f7SMasami Hiramatsu 291ff741783SMasami Hiramatsu /* Searching trace events corresponding to a probe event */ 292ff741783SMasami Hiramatsu ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs); 293ff741783SMasami Hiramatsu 294ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 2954b4da7f7SMasami Hiramatsu 296146a1439SMasami Hiramatsu if (ntevs > 0) { /* Succeeded to find trace events */ 2970e60836bSSrikar Dronamraju pr_debug("find %d probe_trace_events.\n", ntevs); 298190b57fcSMasami Hiramatsu if (module) 299190b57fcSMasami Hiramatsu ret = add_module_to_probe_trace_events(*tevs, ntevs, 300190b57fcSMasami Hiramatsu module); 301190b57fcSMasami Hiramatsu return ret < 0 ? ret : ntevs; 302146a1439SMasami Hiramatsu } 3034b4da7f7SMasami Hiramatsu 304146a1439SMasami Hiramatsu if (ntevs == 0) { /* No error but failed to find probe point. */ 305146a1439SMasami Hiramatsu pr_warning("Probe point '%s' not found.\n", 3064b4da7f7SMasami Hiramatsu synthesize_perf_probe_point(&pev->point)); 307146a1439SMasami Hiramatsu return -ENOENT; 308146a1439SMasami Hiramatsu } 309146a1439SMasami Hiramatsu /* Error path : ntevs < 0 */ 31015eca306SMasami Hiramatsu pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); 31115eca306SMasami Hiramatsu if (ntevs == -EBADF) { 31215eca306SMasami Hiramatsu pr_warning("Warning: No dwarf info found in the vmlinux - " 31315eca306SMasami Hiramatsu "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); 31415eca306SMasami Hiramatsu if (!need_dwarf) { 3150e43e5d2SMasami Hiramatsu pr_debug("Trying to use symbols.\n"); 3164b4da7f7SMasami Hiramatsu return 0; 3174b4da7f7SMasami Hiramatsu } 31815eca306SMasami Hiramatsu } 31915eca306SMasami Hiramatsu return ntevs; 32015eca306SMasami Hiramatsu } 3214b4da7f7SMasami Hiramatsu 3227cf0b79eSMasami Hiramatsu /* 3237cf0b79eSMasami Hiramatsu * Find a src file from a DWARF tag path. Prepend optional source path prefix 3247cf0b79eSMasami Hiramatsu * and chop off leading directories that do not exist. Result is passed back as 3257cf0b79eSMasami Hiramatsu * a newly allocated path on success. 3267cf0b79eSMasami Hiramatsu * Return 0 if file was found and readable, -errno otherwise. 3277cf0b79eSMasami Hiramatsu */ 3286a330a3cSMasami Hiramatsu static int get_real_path(const char *raw_path, const char *comp_dir, 3296a330a3cSMasami Hiramatsu char **new_path) 3307cf0b79eSMasami Hiramatsu { 3316a330a3cSMasami Hiramatsu const char *prefix = symbol_conf.source_prefix; 3326a330a3cSMasami Hiramatsu 3336a330a3cSMasami Hiramatsu if (!prefix) { 3346a330a3cSMasami Hiramatsu if (raw_path[0] != '/' && comp_dir) 3356a330a3cSMasami Hiramatsu /* If not an absolute path, try to use comp_dir */ 3366a330a3cSMasami Hiramatsu prefix = comp_dir; 3376a330a3cSMasami Hiramatsu else { 3387cf0b79eSMasami Hiramatsu if (access(raw_path, R_OK) == 0) { 3397cf0b79eSMasami Hiramatsu *new_path = strdup(raw_path); 3407cf0b79eSMasami Hiramatsu return 0; 3417cf0b79eSMasami Hiramatsu } else 3427cf0b79eSMasami Hiramatsu return -errno; 3437cf0b79eSMasami Hiramatsu } 3446a330a3cSMasami Hiramatsu } 3457cf0b79eSMasami Hiramatsu 3466a330a3cSMasami Hiramatsu *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); 3477cf0b79eSMasami Hiramatsu if (!*new_path) 3487cf0b79eSMasami Hiramatsu return -ENOMEM; 3497cf0b79eSMasami Hiramatsu 3507cf0b79eSMasami Hiramatsu for (;;) { 3516a330a3cSMasami Hiramatsu sprintf(*new_path, "%s/%s", prefix, raw_path); 3527cf0b79eSMasami Hiramatsu 3537cf0b79eSMasami Hiramatsu if (access(*new_path, R_OK) == 0) 3547cf0b79eSMasami Hiramatsu return 0; 3557cf0b79eSMasami Hiramatsu 3566a330a3cSMasami Hiramatsu if (!symbol_conf.source_prefix) 3576a330a3cSMasami Hiramatsu /* In case of searching comp_dir, don't retry */ 3586a330a3cSMasami Hiramatsu return -errno; 3596a330a3cSMasami Hiramatsu 3607cf0b79eSMasami Hiramatsu switch (errno) { 3617cf0b79eSMasami Hiramatsu case ENAMETOOLONG: 3627cf0b79eSMasami Hiramatsu case ENOENT: 3637cf0b79eSMasami Hiramatsu case EROFS: 3647cf0b79eSMasami Hiramatsu case EFAULT: 3657cf0b79eSMasami Hiramatsu raw_path = strchr(++raw_path, '/'); 3667cf0b79eSMasami Hiramatsu if (!raw_path) { 3677cf0b79eSMasami Hiramatsu free(*new_path); 3687cf0b79eSMasami Hiramatsu *new_path = NULL; 3697cf0b79eSMasami Hiramatsu return -ENOENT; 3707cf0b79eSMasami Hiramatsu } 3717cf0b79eSMasami Hiramatsu continue; 3727cf0b79eSMasami Hiramatsu 3737cf0b79eSMasami Hiramatsu default: 3747cf0b79eSMasami Hiramatsu free(*new_path); 3757cf0b79eSMasami Hiramatsu *new_path = NULL; 3767cf0b79eSMasami Hiramatsu return -errno; 3777cf0b79eSMasami Hiramatsu } 3787cf0b79eSMasami Hiramatsu } 3797cf0b79eSMasami Hiramatsu } 3807cf0b79eSMasami Hiramatsu 3814b4da7f7SMasami Hiramatsu #define LINEBUF_SIZE 256 3824b4da7f7SMasami Hiramatsu #define NR_ADDITIONAL_LINES 2 3834b4da7f7SMasami Hiramatsu 384fde52dbdSFranck Bui-Huu static int __show_one_line(FILE *fp, int l, bool skip, bool show_num) 3854b4da7f7SMasami Hiramatsu { 3864b4da7f7SMasami Hiramatsu char buf[LINEBUF_SIZE]; 387befe3414SFranck Bui-Huu const char *color = show_num ? "" : PERF_COLOR_BLUE; 388befe3414SFranck Bui-Huu const char *prefix = NULL; 3894b4da7f7SMasami Hiramatsu 390befe3414SFranck Bui-Huu do { 3914b4da7f7SMasami Hiramatsu if (fgets(buf, LINEBUF_SIZE, fp) == NULL) 3924b4da7f7SMasami Hiramatsu goto error; 393befe3414SFranck Bui-Huu if (skip) 394befe3414SFranck Bui-Huu continue; 395befe3414SFranck Bui-Huu if (!prefix) { 396befe3414SFranck Bui-Huu prefix = show_num ? "%7d " : " "; 397befe3414SFranck Bui-Huu color_fprintf(stdout, color, prefix, l); 3984b4da7f7SMasami Hiramatsu } 399befe3414SFranck Bui-Huu color_fprintf(stdout, color, "%s", buf); 4004b4da7f7SMasami Hiramatsu 401befe3414SFranck Bui-Huu } while (strchr(buf, '\n') == NULL); 402146a1439SMasami Hiramatsu 403fde52dbdSFranck Bui-Huu return 1; 4044b4da7f7SMasami Hiramatsu error: 405fde52dbdSFranck Bui-Huu if (ferror(fp)) { 40632b2b6ecSFranck Bui-Huu pr_warning("File read error: %s\n", strerror(errno)); 407146a1439SMasami Hiramatsu return -1; 4084b4da7f7SMasami Hiramatsu } 409fde52dbdSFranck Bui-Huu return 0; 410fde52dbdSFranck Bui-Huu } 411fde52dbdSFranck Bui-Huu 412fde52dbdSFranck Bui-Huu static int _show_one_line(FILE *fp, int l, bool skip, bool show_num) 413fde52dbdSFranck Bui-Huu { 414fde52dbdSFranck Bui-Huu int rv = __show_one_line(fp, l, skip, show_num); 415fde52dbdSFranck Bui-Huu if (rv == 0) { 416fde52dbdSFranck Bui-Huu pr_warning("Source file is shorter than expected.\n"); 417fde52dbdSFranck Bui-Huu rv = -1; 418fde52dbdSFranck Bui-Huu } 419fde52dbdSFranck Bui-Huu return rv; 420fde52dbdSFranck Bui-Huu } 421fde52dbdSFranck Bui-Huu 422fde52dbdSFranck Bui-Huu #define show_one_line_with_num(f,l) _show_one_line(f,l,false,true) 423fde52dbdSFranck Bui-Huu #define show_one_line(f,l) _show_one_line(f,l,false,false) 424fde52dbdSFranck Bui-Huu #define skip_one_line(f,l) _show_one_line(f,l,true,false) 425fde52dbdSFranck Bui-Huu #define show_one_line_or_eof(f,l) __show_one_line(f,l,false,false) 4264b4da7f7SMasami Hiramatsu 4274b4da7f7SMasami Hiramatsu /* 4284b4da7f7SMasami Hiramatsu * Show line-range always requires debuginfo to find source file and 4294b4da7f7SMasami Hiramatsu * line number. 4304b4da7f7SMasami Hiramatsu */ 431469b9b88SMasami Hiramatsu int show_line_range(struct line_range *lr, const char *module) 4324b4da7f7SMasami Hiramatsu { 433d3b63d7aSMasami Hiramatsu int l = 1; 4344b4da7f7SMasami Hiramatsu struct line_node *ln; 435ff741783SMasami Hiramatsu struct debuginfo *dinfo; 4364b4da7f7SMasami Hiramatsu FILE *fp; 437ff741783SMasami Hiramatsu int ret; 4387cf0b79eSMasami Hiramatsu char *tmp; 4394b4da7f7SMasami Hiramatsu 4404b4da7f7SMasami Hiramatsu /* Search a line range */ 441146a1439SMasami Hiramatsu ret = init_vmlinux(); 442146a1439SMasami Hiramatsu if (ret < 0) 443146a1439SMasami Hiramatsu return ret; 444146a1439SMasami Hiramatsu 445ff741783SMasami Hiramatsu dinfo = open_debuginfo(module); 446ff741783SMasami Hiramatsu if (!dinfo) { 447146a1439SMasami Hiramatsu pr_warning("Failed to open debuginfo file.\n"); 448ff741783SMasami Hiramatsu return -ENOENT; 449146a1439SMasami Hiramatsu } 450146a1439SMasami Hiramatsu 451ff741783SMasami Hiramatsu ret = debuginfo__find_line_range(dinfo, lr); 452ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 453146a1439SMasami Hiramatsu if (ret == 0) { 454146a1439SMasami Hiramatsu pr_warning("Specified source line is not found.\n"); 455146a1439SMasami Hiramatsu return -ENOENT; 456146a1439SMasami Hiramatsu } else if (ret < 0) { 457146a1439SMasami Hiramatsu pr_warning("Debuginfo analysis failed. (%d)\n", ret); 458146a1439SMasami Hiramatsu return ret; 459146a1439SMasami Hiramatsu } 4604b4da7f7SMasami Hiramatsu 4617cf0b79eSMasami Hiramatsu /* Convert source file path */ 4627cf0b79eSMasami Hiramatsu tmp = lr->path; 4636a330a3cSMasami Hiramatsu ret = get_real_path(tmp, lr->comp_dir, &lr->path); 4647cf0b79eSMasami Hiramatsu free(tmp); /* Free old path */ 4657cf0b79eSMasami Hiramatsu if (ret < 0) { 4667cf0b79eSMasami Hiramatsu pr_warning("Failed to find source file. (%d)\n", ret); 4677cf0b79eSMasami Hiramatsu return ret; 4687cf0b79eSMasami Hiramatsu } 4697cf0b79eSMasami Hiramatsu 4704b4da7f7SMasami Hiramatsu setup_pager(); 4714b4da7f7SMasami Hiramatsu 4724b4da7f7SMasami Hiramatsu if (lr->function) 4738737ebdeSMasami Hiramatsu fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path, 4744b4da7f7SMasami Hiramatsu lr->start - lr->offset); 4754b4da7f7SMasami Hiramatsu else 47662c15fc4SFranck Bui-Huu fprintf(stdout, "<%s:%d>\n", lr->path, lr->start); 4774b4da7f7SMasami Hiramatsu 4784b4da7f7SMasami Hiramatsu fp = fopen(lr->path, "r"); 479146a1439SMasami Hiramatsu if (fp == NULL) { 480146a1439SMasami Hiramatsu pr_warning("Failed to open %s: %s\n", lr->path, 481146a1439SMasami Hiramatsu strerror(errno)); 482146a1439SMasami Hiramatsu return -errno; 483146a1439SMasami Hiramatsu } 4844b4da7f7SMasami Hiramatsu /* Skip to starting line number */ 48544b81e92SFranck Bui-Huu while (l < lr->start) { 486fde52dbdSFranck Bui-Huu ret = skip_one_line(fp, l++); 487146a1439SMasami Hiramatsu if (ret < 0) 488146a1439SMasami Hiramatsu goto end; 48944b81e92SFranck Bui-Huu } 4904b4da7f7SMasami Hiramatsu 4914b4da7f7SMasami Hiramatsu list_for_each_entry(ln, &lr->line_list, list) { 49244b81e92SFranck Bui-Huu for (; ln->line > l; l++) { 493fde52dbdSFranck Bui-Huu ret = show_one_line(fp, l - lr->offset); 49444b81e92SFranck Bui-Huu if (ret < 0) 49544b81e92SFranck Bui-Huu goto end; 49644b81e92SFranck Bui-Huu } 497fde52dbdSFranck Bui-Huu ret = show_one_line_with_num(fp, l++ - lr->offset); 498146a1439SMasami Hiramatsu if (ret < 0) 499146a1439SMasami Hiramatsu goto end; 5004b4da7f7SMasami Hiramatsu } 5014b4da7f7SMasami Hiramatsu 5024b4da7f7SMasami Hiramatsu if (lr->end == INT_MAX) 5034b4da7f7SMasami Hiramatsu lr->end = l + NR_ADDITIONAL_LINES; 504fde52dbdSFranck Bui-Huu while (l <= lr->end) { 505fde52dbdSFranck Bui-Huu ret = show_one_line_or_eof(fp, l++ - lr->offset); 506fde52dbdSFranck Bui-Huu if (ret <= 0) 50744b81e92SFranck Bui-Huu break; 50844b81e92SFranck Bui-Huu } 509146a1439SMasami Hiramatsu end: 5104b4da7f7SMasami Hiramatsu fclose(fp); 511146a1439SMasami Hiramatsu return ret; 5124b4da7f7SMasami Hiramatsu } 5134b4da7f7SMasami Hiramatsu 514ff741783SMasami Hiramatsu static int show_available_vars_at(struct debuginfo *dinfo, 515ff741783SMasami Hiramatsu struct perf_probe_event *pev, 516bd09d7b5SMasami Hiramatsu int max_vls, struct strfilter *_filter, 517bd09d7b5SMasami Hiramatsu bool externs) 518cf6eb489SMasami Hiramatsu { 519cf6eb489SMasami Hiramatsu char *buf; 520bd09d7b5SMasami Hiramatsu int ret, i, nvars; 521cf6eb489SMasami Hiramatsu struct str_node *node; 522cf6eb489SMasami Hiramatsu struct variable_list *vls = NULL, *vl; 523bd09d7b5SMasami Hiramatsu const char *var; 524cf6eb489SMasami Hiramatsu 525cf6eb489SMasami Hiramatsu buf = synthesize_perf_probe_point(&pev->point); 526cf6eb489SMasami Hiramatsu if (!buf) 527cf6eb489SMasami Hiramatsu return -EINVAL; 528cf6eb489SMasami Hiramatsu pr_debug("Searching variables at %s\n", buf); 529cf6eb489SMasami Hiramatsu 530ff741783SMasami Hiramatsu ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, 531ff741783SMasami Hiramatsu max_vls, externs); 532bd09d7b5SMasami Hiramatsu if (ret <= 0) { 533bd09d7b5SMasami Hiramatsu pr_err("Failed to find variables at %s (%d)\n", buf, ret); 534bd09d7b5SMasami Hiramatsu goto end; 535bd09d7b5SMasami Hiramatsu } 536bd09d7b5SMasami Hiramatsu /* Some variables are found */ 537cf6eb489SMasami Hiramatsu fprintf(stdout, "Available variables at %s\n", buf); 538cf6eb489SMasami Hiramatsu for (i = 0; i < ret; i++) { 539cf6eb489SMasami Hiramatsu vl = &vls[i]; 540cf6eb489SMasami Hiramatsu /* 541cf6eb489SMasami Hiramatsu * A probe point might be converted to 542cf6eb489SMasami Hiramatsu * several trace points. 543cf6eb489SMasami Hiramatsu */ 544cf6eb489SMasami Hiramatsu fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, 545cf6eb489SMasami Hiramatsu vl->point.offset); 546cf6eb489SMasami Hiramatsu free(vl->point.symbol); 547bd09d7b5SMasami Hiramatsu nvars = 0; 548cf6eb489SMasami Hiramatsu if (vl->vars) { 549bd09d7b5SMasami Hiramatsu strlist__for_each(node, vl->vars) { 550bd09d7b5SMasami Hiramatsu var = strchr(node->s, '\t') + 1; 551bd09d7b5SMasami Hiramatsu if (strfilter__compare(_filter, var)) { 552cf6eb489SMasami Hiramatsu fprintf(stdout, "\t\t%s\n", node->s); 553bd09d7b5SMasami Hiramatsu nvars++; 554bd09d7b5SMasami Hiramatsu } 555bd09d7b5SMasami Hiramatsu } 556cf6eb489SMasami Hiramatsu strlist__delete(vl->vars); 557bd09d7b5SMasami Hiramatsu } 558bd09d7b5SMasami Hiramatsu if (nvars == 0) 559bd09d7b5SMasami Hiramatsu fprintf(stdout, "\t\t(No matched variables)\n"); 560cf6eb489SMasami Hiramatsu } 561cf6eb489SMasami Hiramatsu free(vls); 562bd09d7b5SMasami Hiramatsu end: 563cf6eb489SMasami Hiramatsu free(buf); 564cf6eb489SMasami Hiramatsu return ret; 565cf6eb489SMasami Hiramatsu } 566cf6eb489SMasami Hiramatsu 567cf6eb489SMasami Hiramatsu /* Show available variables on given probe point */ 568cf6eb489SMasami Hiramatsu int show_available_vars(struct perf_probe_event *pevs, int npevs, 569bd09d7b5SMasami Hiramatsu int max_vls, const char *module, 570bd09d7b5SMasami Hiramatsu struct strfilter *_filter, bool externs) 571cf6eb489SMasami Hiramatsu { 572ff741783SMasami Hiramatsu int i, ret = 0; 573ff741783SMasami Hiramatsu struct debuginfo *dinfo; 574cf6eb489SMasami Hiramatsu 575cf6eb489SMasami Hiramatsu ret = init_vmlinux(); 576cf6eb489SMasami Hiramatsu if (ret < 0) 577cf6eb489SMasami Hiramatsu return ret; 578cf6eb489SMasami Hiramatsu 579ff741783SMasami Hiramatsu dinfo = open_debuginfo(module); 580ff741783SMasami Hiramatsu if (!dinfo) { 581ff741783SMasami Hiramatsu pr_warning("Failed to open debuginfo file.\n"); 582ff741783SMasami Hiramatsu return -ENOENT; 583ff741783SMasami Hiramatsu } 584ff741783SMasami Hiramatsu 585cc446446SMasami Hiramatsu setup_pager(); 586cc446446SMasami Hiramatsu 587ff741783SMasami Hiramatsu for (i = 0; i < npevs && ret >= 0; i++) 588ff741783SMasami Hiramatsu ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter, 589bd09d7b5SMasami Hiramatsu externs); 590ff741783SMasami Hiramatsu 591ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 592cf6eb489SMasami Hiramatsu return ret; 593cf6eb489SMasami Hiramatsu } 594cf6eb489SMasami Hiramatsu 5954b4da7f7SMasami Hiramatsu #else /* !DWARF_SUPPORT */ 5964b4da7f7SMasami Hiramatsu 5970e60836bSSrikar Dronamraju static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 5984b4da7f7SMasami Hiramatsu struct perf_probe_point *pp) 5994b4da7f7SMasami Hiramatsu { 600469b9b88SMasami Hiramatsu struct symbol *sym; 601469b9b88SMasami Hiramatsu 602469b9b88SMasami Hiramatsu sym = __find_kernel_function_by_name(tp->symbol, NULL); 603469b9b88SMasami Hiramatsu if (!sym) { 604469b9b88SMasami Hiramatsu pr_err("Failed to find symbol %s in kernel.\n", tp->symbol); 605469b9b88SMasami Hiramatsu return -ENOENT; 606469b9b88SMasami Hiramatsu } 60702b95dadSMasami Hiramatsu pp->function = strdup(tp->symbol); 60802b95dadSMasami Hiramatsu if (pp->function == NULL) 60902b95dadSMasami Hiramatsu return -ENOMEM; 6104b4da7f7SMasami Hiramatsu pp->offset = tp->offset; 6114b4da7f7SMasami Hiramatsu pp->retprobe = tp->retprobe; 612146a1439SMasami Hiramatsu 613146a1439SMasami Hiramatsu return 0; 6144b4da7f7SMasami Hiramatsu } 6154b4da7f7SMasami Hiramatsu 6160e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 6170e60836bSSrikar Dronamraju struct probe_trace_event **tevs __unused, 618469b9b88SMasami Hiramatsu int max_tevs __unused, const char *mod __unused) 6194b4da7f7SMasami Hiramatsu { 620146a1439SMasami Hiramatsu if (perf_probe_event_need_dwarf(pev)) { 621146a1439SMasami Hiramatsu pr_warning("Debuginfo-analysis is not supported.\n"); 622146a1439SMasami Hiramatsu return -ENOSYS; 623146a1439SMasami Hiramatsu } 6244b4da7f7SMasami Hiramatsu return 0; 6254b4da7f7SMasami Hiramatsu } 6264b4da7f7SMasami Hiramatsu 627469b9b88SMasami Hiramatsu int show_line_range(struct line_range *lr __unused, const char *module __unused) 6284b4da7f7SMasami Hiramatsu { 629146a1439SMasami Hiramatsu pr_warning("Debuginfo-analysis is not supported.\n"); 630146a1439SMasami Hiramatsu return -ENOSYS; 6314b4da7f7SMasami Hiramatsu } 6324b4da7f7SMasami Hiramatsu 633cf6eb489SMasami Hiramatsu int show_available_vars(struct perf_probe_event *pevs __unused, 634469b9b88SMasami Hiramatsu int npevs __unused, int max_vls __unused, 635bd09d7b5SMasami Hiramatsu const char *module __unused, 636bd09d7b5SMasami Hiramatsu struct strfilter *filter __unused, 637bd09d7b5SMasami Hiramatsu bool externs __unused) 638cf6eb489SMasami Hiramatsu { 639cf6eb489SMasami Hiramatsu pr_warning("Debuginfo-analysis is not supported.\n"); 640cf6eb489SMasami Hiramatsu return -ENOSYS; 641cf6eb489SMasami Hiramatsu } 642e0faa8d3SMasami Hiramatsu #endif 643e0faa8d3SMasami Hiramatsu 64421dd9ae5SFranck Bui-Huu static int parse_line_num(char **ptr, int *val, const char *what) 64521dd9ae5SFranck Bui-Huu { 64621dd9ae5SFranck Bui-Huu const char *start = *ptr; 64721dd9ae5SFranck Bui-Huu 64821dd9ae5SFranck Bui-Huu errno = 0; 64921dd9ae5SFranck Bui-Huu *val = strtol(*ptr, ptr, 0); 65021dd9ae5SFranck Bui-Huu if (errno || *ptr == start) { 65121dd9ae5SFranck Bui-Huu semantic_error("'%s' is not a valid number.\n", what); 65221dd9ae5SFranck Bui-Huu return -EINVAL; 65321dd9ae5SFranck Bui-Huu } 65421dd9ae5SFranck Bui-Huu return 0; 65521dd9ae5SFranck Bui-Huu } 65621dd9ae5SFranck Bui-Huu 6579d95b580SFranck Bui-Huu /* 6589d95b580SFranck Bui-Huu * Stuff 'lr' according to the line range described by 'arg'. 6599d95b580SFranck Bui-Huu * The line range syntax is described by: 6609d95b580SFranck Bui-Huu * 6619d95b580SFranck Bui-Huu * SRC[:SLN[+NUM|-ELN]] 662e116dfa1SMasami Hiramatsu * FNC[@SRC][:SLN[+NUM|-ELN]] 6639d95b580SFranck Bui-Huu */ 664146a1439SMasami Hiramatsu int parse_line_range_desc(const char *arg, struct line_range *lr) 665631c9defSMasami Hiramatsu { 666e116dfa1SMasami Hiramatsu char *range, *file, *name = strdup(arg); 66721dd9ae5SFranck Bui-Huu int err; 6689d95b580SFranck Bui-Huu 66921dd9ae5SFranck Bui-Huu if (!name) 67021dd9ae5SFranck Bui-Huu return -ENOMEM; 67121dd9ae5SFranck Bui-Huu 67221dd9ae5SFranck Bui-Huu lr->start = 0; 67321dd9ae5SFranck Bui-Huu lr->end = INT_MAX; 67421dd9ae5SFranck Bui-Huu 67521dd9ae5SFranck Bui-Huu range = strchr(name, ':'); 67621dd9ae5SFranck Bui-Huu if (range) { 67721dd9ae5SFranck Bui-Huu *range++ = '\0'; 67821dd9ae5SFranck Bui-Huu 67921dd9ae5SFranck Bui-Huu err = parse_line_num(&range, &lr->start, "start line"); 68021dd9ae5SFranck Bui-Huu if (err) 68121dd9ae5SFranck Bui-Huu goto err; 68221dd9ae5SFranck Bui-Huu 68321dd9ae5SFranck Bui-Huu if (*range == '+' || *range == '-') { 68421dd9ae5SFranck Bui-Huu const char c = *range++; 68521dd9ae5SFranck Bui-Huu 68621dd9ae5SFranck Bui-Huu err = parse_line_num(&range, &lr->end, "end line"); 68721dd9ae5SFranck Bui-Huu if (err) 68821dd9ae5SFranck Bui-Huu goto err; 68921dd9ae5SFranck Bui-Huu 69021dd9ae5SFranck Bui-Huu if (c == '+') { 69121dd9ae5SFranck Bui-Huu lr->end += lr->start; 69221dd9ae5SFranck Bui-Huu /* 693dda4ab34SMasami Hiramatsu * Adjust the number of lines here. 694dda4ab34SMasami Hiramatsu * If the number of lines == 1, the 695dda4ab34SMasami Hiramatsu * the end of line should be equal to 696dda4ab34SMasami Hiramatsu * the start of line. 697dda4ab34SMasami Hiramatsu */ 69821dd9ae5SFranck Bui-Huu lr->end--; 69921dd9ae5SFranck Bui-Huu } 70021dd9ae5SFranck Bui-Huu } 70121dd9ae5SFranck Bui-Huu 702d3b63d7aSMasami Hiramatsu pr_debug("Line range is %d to %d\n", lr->start, lr->end); 70321dd9ae5SFranck Bui-Huu 70421dd9ae5SFranck Bui-Huu err = -EINVAL; 705d3b63d7aSMasami Hiramatsu if (lr->start > lr->end) { 706631c9defSMasami Hiramatsu semantic_error("Start line must be smaller" 707146a1439SMasami Hiramatsu " than end line.\n"); 70821dd9ae5SFranck Bui-Huu goto err; 709146a1439SMasami Hiramatsu } 71021dd9ae5SFranck Bui-Huu if (*range != '\0') { 71121dd9ae5SFranck Bui-Huu semantic_error("Tailing with invalid str '%s'.\n", range); 71221dd9ae5SFranck Bui-Huu goto err; 713146a1439SMasami Hiramatsu } 714d3b63d7aSMasami Hiramatsu } 71502b95dadSMasami Hiramatsu 716e116dfa1SMasami Hiramatsu file = strchr(name, '@'); 717e116dfa1SMasami Hiramatsu if (file) { 718e116dfa1SMasami Hiramatsu *file = '\0'; 719e116dfa1SMasami Hiramatsu lr->file = strdup(++file); 720e116dfa1SMasami Hiramatsu if (lr->file == NULL) { 721e116dfa1SMasami Hiramatsu err = -ENOMEM; 722e116dfa1SMasami Hiramatsu goto err; 723e116dfa1SMasami Hiramatsu } 724e116dfa1SMasami Hiramatsu lr->function = name; 725e116dfa1SMasami Hiramatsu } else if (strchr(name, '.')) 72621dd9ae5SFranck Bui-Huu lr->file = name; 727631c9defSMasami Hiramatsu else 72821dd9ae5SFranck Bui-Huu lr->function = name; 729146a1439SMasami Hiramatsu 730146a1439SMasami Hiramatsu return 0; 73121dd9ae5SFranck Bui-Huu err: 73221dd9ae5SFranck Bui-Huu free(name); 73321dd9ae5SFranck Bui-Huu return err; 734631c9defSMasami Hiramatsu } 735631c9defSMasami Hiramatsu 736b7702a21SMasami Hiramatsu /* Check the name is good for event/group */ 737b7702a21SMasami Hiramatsu static bool check_event_name(const char *name) 738b7702a21SMasami Hiramatsu { 739b7702a21SMasami Hiramatsu if (!isalpha(*name) && *name != '_') 740b7702a21SMasami Hiramatsu return false; 741b7702a21SMasami Hiramatsu while (*++name != '\0') { 742b7702a21SMasami Hiramatsu if (!isalpha(*name) && !isdigit(*name) && *name != '_') 743b7702a21SMasami Hiramatsu return false; 744b7702a21SMasami Hiramatsu } 745b7702a21SMasami Hiramatsu return true; 746b7702a21SMasami Hiramatsu } 747b7702a21SMasami Hiramatsu 74850656eecSMasami Hiramatsu /* Parse probepoint definition. */ 749146a1439SMasami Hiramatsu static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) 75050656eecSMasami Hiramatsu { 7514235b045SMasami Hiramatsu struct perf_probe_point *pp = &pev->point; 75250656eecSMasami Hiramatsu char *ptr, *tmp; 75350656eecSMasami Hiramatsu char c, nc = 0; 75450656eecSMasami Hiramatsu /* 75550656eecSMasami Hiramatsu * <Syntax> 7562a9c8c36SMasami Hiramatsu * perf probe [EVENT=]SRC[:LN|;PTN] 7572a9c8c36SMasami Hiramatsu * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] 758af663d75SMasami Hiramatsu * 759af663d75SMasami Hiramatsu * TODO:Group name support 76050656eecSMasami Hiramatsu */ 76150656eecSMasami Hiramatsu 7622a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";=@+%"); 7632a9c8c36SMasami Hiramatsu if (ptr && *ptr == '=') { /* Event name */ 764af663d75SMasami Hiramatsu *ptr = '\0'; 765af663d75SMasami Hiramatsu tmp = ptr + 1; 766146a1439SMasami Hiramatsu if (strchr(arg, ':')) { 767146a1439SMasami Hiramatsu semantic_error("Group name is not supported yet.\n"); 768146a1439SMasami Hiramatsu return -ENOTSUP; 769146a1439SMasami Hiramatsu } 770146a1439SMasami Hiramatsu if (!check_event_name(arg)) { 771b7702a21SMasami Hiramatsu semantic_error("%s is bad for event name -it must " 772146a1439SMasami Hiramatsu "follow C symbol-naming rule.\n", arg); 773146a1439SMasami Hiramatsu return -EINVAL; 774146a1439SMasami Hiramatsu } 77502b95dadSMasami Hiramatsu pev->event = strdup(arg); 77602b95dadSMasami Hiramatsu if (pev->event == NULL) 77702b95dadSMasami Hiramatsu return -ENOMEM; 7784235b045SMasami Hiramatsu pev->group = NULL; 779af663d75SMasami Hiramatsu arg = tmp; 780af663d75SMasami Hiramatsu } 781af663d75SMasami Hiramatsu 7822a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";:+@%"); 78350656eecSMasami Hiramatsu if (ptr) { 78450656eecSMasami Hiramatsu nc = *ptr; 78550656eecSMasami Hiramatsu *ptr++ = '\0'; 78650656eecSMasami Hiramatsu } 78750656eecSMasami Hiramatsu 78802b95dadSMasami Hiramatsu tmp = strdup(arg); 78902b95dadSMasami Hiramatsu if (tmp == NULL) 79002b95dadSMasami Hiramatsu return -ENOMEM; 79102b95dadSMasami Hiramatsu 79250656eecSMasami Hiramatsu /* Check arg is function or file and copy it */ 79302b95dadSMasami Hiramatsu if (strchr(tmp, '.')) /* File */ 79402b95dadSMasami Hiramatsu pp->file = tmp; 79550656eecSMasami Hiramatsu else /* Function */ 79602b95dadSMasami Hiramatsu pp->function = tmp; 79750656eecSMasami Hiramatsu 79850656eecSMasami Hiramatsu /* Parse other options */ 79950656eecSMasami Hiramatsu while (ptr) { 80050656eecSMasami Hiramatsu arg = ptr; 80150656eecSMasami Hiramatsu c = nc; 8022a9c8c36SMasami Hiramatsu if (c == ';') { /* Lazy pattern must be the last part */ 80302b95dadSMasami Hiramatsu pp->lazy_line = strdup(arg); 80402b95dadSMasami Hiramatsu if (pp->lazy_line == NULL) 80502b95dadSMasami Hiramatsu return -ENOMEM; 8062a9c8c36SMasami Hiramatsu break; 8072a9c8c36SMasami Hiramatsu } 8082a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";:+@%"); 80950656eecSMasami Hiramatsu if (ptr) { 81050656eecSMasami Hiramatsu nc = *ptr; 81150656eecSMasami Hiramatsu *ptr++ = '\0'; 81250656eecSMasami Hiramatsu } 81350656eecSMasami Hiramatsu switch (c) { 81450656eecSMasami Hiramatsu case ':': /* Line number */ 81550656eecSMasami Hiramatsu pp->line = strtoul(arg, &tmp, 0); 816146a1439SMasami Hiramatsu if (*tmp != '\0') { 8172a9c8c36SMasami Hiramatsu semantic_error("There is non-digit char" 818146a1439SMasami Hiramatsu " in line number.\n"); 819146a1439SMasami Hiramatsu return -EINVAL; 820146a1439SMasami Hiramatsu } 82150656eecSMasami Hiramatsu break; 82250656eecSMasami Hiramatsu case '+': /* Byte offset from a symbol */ 82350656eecSMasami Hiramatsu pp->offset = strtoul(arg, &tmp, 0); 824146a1439SMasami Hiramatsu if (*tmp != '\0') { 8252a9c8c36SMasami Hiramatsu semantic_error("There is non-digit character" 826146a1439SMasami Hiramatsu " in offset.\n"); 827146a1439SMasami Hiramatsu return -EINVAL; 828146a1439SMasami Hiramatsu } 82950656eecSMasami Hiramatsu break; 83050656eecSMasami Hiramatsu case '@': /* File name */ 831146a1439SMasami Hiramatsu if (pp->file) { 832146a1439SMasami Hiramatsu semantic_error("SRC@SRC is not allowed.\n"); 833146a1439SMasami Hiramatsu return -EINVAL; 834146a1439SMasami Hiramatsu } 83502b95dadSMasami Hiramatsu pp->file = strdup(arg); 83602b95dadSMasami Hiramatsu if (pp->file == NULL) 83702b95dadSMasami Hiramatsu return -ENOMEM; 83850656eecSMasami Hiramatsu break; 83950656eecSMasami Hiramatsu case '%': /* Probe places */ 84050656eecSMasami Hiramatsu if (strcmp(arg, "return") == 0) { 84150656eecSMasami Hiramatsu pp->retprobe = 1; 842146a1439SMasami Hiramatsu } else { /* Others not supported yet */ 843146a1439SMasami Hiramatsu semantic_error("%%%s is not supported.\n", arg); 844146a1439SMasami Hiramatsu return -ENOTSUP; 845146a1439SMasami Hiramatsu } 84650656eecSMasami Hiramatsu break; 847146a1439SMasami Hiramatsu default: /* Buggy case */ 848146a1439SMasami Hiramatsu pr_err("This program has a bug at %s:%d.\n", 849146a1439SMasami Hiramatsu __FILE__, __LINE__); 850146a1439SMasami Hiramatsu return -ENOTSUP; 85150656eecSMasami Hiramatsu break; 85250656eecSMasami Hiramatsu } 85350656eecSMasami Hiramatsu } 85450656eecSMasami Hiramatsu 85550656eecSMasami Hiramatsu /* Exclusion check */ 856146a1439SMasami Hiramatsu if (pp->lazy_line && pp->line) { 8570e43e5d2SMasami Hiramatsu semantic_error("Lazy pattern can't be used with" 8580e43e5d2SMasami Hiramatsu " line number.\n"); 859146a1439SMasami Hiramatsu return -EINVAL; 860146a1439SMasami Hiramatsu } 8612a9c8c36SMasami Hiramatsu 862146a1439SMasami Hiramatsu if (pp->lazy_line && pp->offset) { 8630e43e5d2SMasami Hiramatsu semantic_error("Lazy pattern can't be used with offset.\n"); 864146a1439SMasami Hiramatsu return -EINVAL; 865146a1439SMasami Hiramatsu } 8662a9c8c36SMasami Hiramatsu 867146a1439SMasami Hiramatsu if (pp->line && pp->offset) { 8680e43e5d2SMasami Hiramatsu semantic_error("Offset can't be used with line number.\n"); 869146a1439SMasami Hiramatsu return -EINVAL; 870146a1439SMasami Hiramatsu } 87150656eecSMasami Hiramatsu 872146a1439SMasami Hiramatsu if (!pp->line && !pp->lazy_line && pp->file && !pp->function) { 8732a9c8c36SMasami Hiramatsu semantic_error("File always requires line number or " 8740e43e5d2SMasami Hiramatsu "lazy pattern.\n"); 875146a1439SMasami Hiramatsu return -EINVAL; 876146a1439SMasami Hiramatsu } 87750656eecSMasami Hiramatsu 878146a1439SMasami Hiramatsu if (pp->offset && !pp->function) { 8790e43e5d2SMasami Hiramatsu semantic_error("Offset requires an entry function.\n"); 880146a1439SMasami Hiramatsu return -EINVAL; 881146a1439SMasami Hiramatsu } 88250656eecSMasami Hiramatsu 883146a1439SMasami Hiramatsu if (pp->retprobe && !pp->function) { 8840e43e5d2SMasami Hiramatsu semantic_error("Return probe requires an entry function.\n"); 885146a1439SMasami Hiramatsu return -EINVAL; 886146a1439SMasami Hiramatsu } 88750656eecSMasami Hiramatsu 888146a1439SMasami Hiramatsu if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { 8892a9c8c36SMasami Hiramatsu semantic_error("Offset/Line/Lazy pattern can't be used with " 8900e43e5d2SMasami Hiramatsu "return probe.\n"); 891146a1439SMasami Hiramatsu return -EINVAL; 892146a1439SMasami Hiramatsu } 89350656eecSMasami Hiramatsu 8944235b045SMasami Hiramatsu pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n", 8952a9c8c36SMasami Hiramatsu pp->function, pp->file, pp->line, pp->offset, pp->retprobe, 8962a9c8c36SMasami Hiramatsu pp->lazy_line); 897146a1439SMasami Hiramatsu return 0; 89850656eecSMasami Hiramatsu } 89950656eecSMasami Hiramatsu 9007df2f329SMasami Hiramatsu /* Parse perf-probe event argument */ 901146a1439SMasami Hiramatsu static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) 9027df2f329SMasami Hiramatsu { 903b2a3c12bSMasami Hiramatsu char *tmp, *goodname; 9047df2f329SMasami Hiramatsu struct perf_probe_arg_field **fieldp; 9057df2f329SMasami Hiramatsu 9067df2f329SMasami Hiramatsu pr_debug("parsing arg: %s into ", str); 9077df2f329SMasami Hiramatsu 90848481938SMasami Hiramatsu tmp = strchr(str, '='); 90948481938SMasami Hiramatsu if (tmp) { 91002b95dadSMasami Hiramatsu arg->name = strndup(str, tmp - str); 91102b95dadSMasami Hiramatsu if (arg->name == NULL) 91202b95dadSMasami Hiramatsu return -ENOMEM; 91311a1ca35SMasami Hiramatsu pr_debug("name:%s ", arg->name); 91448481938SMasami Hiramatsu str = tmp + 1; 91548481938SMasami Hiramatsu } 91648481938SMasami Hiramatsu 91711a1ca35SMasami Hiramatsu tmp = strchr(str, ':'); 91811a1ca35SMasami Hiramatsu if (tmp) { /* Type setting */ 91911a1ca35SMasami Hiramatsu *tmp = '\0'; 92002b95dadSMasami Hiramatsu arg->type = strdup(tmp + 1); 92102b95dadSMasami Hiramatsu if (arg->type == NULL) 92202b95dadSMasami Hiramatsu return -ENOMEM; 92311a1ca35SMasami Hiramatsu pr_debug("type:%s ", arg->type); 92411a1ca35SMasami Hiramatsu } 92511a1ca35SMasami Hiramatsu 926b2a3c12bSMasami Hiramatsu tmp = strpbrk(str, "-.["); 9277df2f329SMasami Hiramatsu if (!is_c_varname(str) || !tmp) { 9287df2f329SMasami Hiramatsu /* A variable, register, symbol or special value */ 92902b95dadSMasami Hiramatsu arg->var = strdup(str); 93002b95dadSMasami Hiramatsu if (arg->var == NULL) 93102b95dadSMasami Hiramatsu return -ENOMEM; 93248481938SMasami Hiramatsu pr_debug("%s\n", arg->var); 933146a1439SMasami Hiramatsu return 0; 9347df2f329SMasami Hiramatsu } 9357df2f329SMasami Hiramatsu 936b2a3c12bSMasami Hiramatsu /* Structure fields or array element */ 93702b95dadSMasami Hiramatsu arg->var = strndup(str, tmp - str); 93802b95dadSMasami Hiramatsu if (arg->var == NULL) 93902b95dadSMasami Hiramatsu return -ENOMEM; 940b2a3c12bSMasami Hiramatsu goodname = arg->var; 94148481938SMasami Hiramatsu pr_debug("%s, ", arg->var); 9427df2f329SMasami Hiramatsu fieldp = &arg->field; 9437df2f329SMasami Hiramatsu 9447df2f329SMasami Hiramatsu do { 945e334016fSMasami Hiramatsu *fieldp = zalloc(sizeof(struct perf_probe_arg_field)); 946e334016fSMasami Hiramatsu if (*fieldp == NULL) 947e334016fSMasami Hiramatsu return -ENOMEM; 948b2a3c12bSMasami Hiramatsu if (*tmp == '[') { /* Array */ 949b2a3c12bSMasami Hiramatsu str = tmp; 950b2a3c12bSMasami Hiramatsu (*fieldp)->index = strtol(str + 1, &tmp, 0); 951b2a3c12bSMasami Hiramatsu (*fieldp)->ref = true; 952b2a3c12bSMasami Hiramatsu if (*tmp != ']' || tmp == str + 1) { 953b2a3c12bSMasami Hiramatsu semantic_error("Array index must be a" 954b2a3c12bSMasami Hiramatsu " number.\n"); 955b2a3c12bSMasami Hiramatsu return -EINVAL; 956b2a3c12bSMasami Hiramatsu } 957b2a3c12bSMasami Hiramatsu tmp++; 958b2a3c12bSMasami Hiramatsu if (*tmp == '\0') 959b2a3c12bSMasami Hiramatsu tmp = NULL; 960b2a3c12bSMasami Hiramatsu } else { /* Structure */ 9617df2f329SMasami Hiramatsu if (*tmp == '.') { 9627df2f329SMasami Hiramatsu str = tmp + 1; 9637df2f329SMasami Hiramatsu (*fieldp)->ref = false; 9647df2f329SMasami Hiramatsu } else if (tmp[1] == '>') { 9657df2f329SMasami Hiramatsu str = tmp + 2; 9667df2f329SMasami Hiramatsu (*fieldp)->ref = true; 967146a1439SMasami Hiramatsu } else { 968b2a3c12bSMasami Hiramatsu semantic_error("Argument parse error: %s\n", 969b2a3c12bSMasami Hiramatsu str); 970146a1439SMasami Hiramatsu return -EINVAL; 971146a1439SMasami Hiramatsu } 972b2a3c12bSMasami Hiramatsu tmp = strpbrk(str, "-.["); 973b2a3c12bSMasami Hiramatsu } 9747df2f329SMasami Hiramatsu if (tmp) { 97502b95dadSMasami Hiramatsu (*fieldp)->name = strndup(str, tmp - str); 97602b95dadSMasami Hiramatsu if ((*fieldp)->name == NULL) 97702b95dadSMasami Hiramatsu return -ENOMEM; 978b2a3c12bSMasami Hiramatsu if (*str != '[') 979b2a3c12bSMasami Hiramatsu goodname = (*fieldp)->name; 9807df2f329SMasami Hiramatsu pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); 9817df2f329SMasami Hiramatsu fieldp = &(*fieldp)->next; 9827df2f329SMasami Hiramatsu } 9837df2f329SMasami Hiramatsu } while (tmp); 98402b95dadSMasami Hiramatsu (*fieldp)->name = strdup(str); 98502b95dadSMasami Hiramatsu if ((*fieldp)->name == NULL) 98602b95dadSMasami Hiramatsu return -ENOMEM; 987b2a3c12bSMasami Hiramatsu if (*str != '[') 988b2a3c12bSMasami Hiramatsu goodname = (*fieldp)->name; 9897df2f329SMasami Hiramatsu pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); 990df0faf4bSMasami Hiramatsu 991b2a3c12bSMasami Hiramatsu /* If no name is specified, set the last field name (not array index)*/ 99202b95dadSMasami Hiramatsu if (!arg->name) { 993b2a3c12bSMasami Hiramatsu arg->name = strdup(goodname); 99402b95dadSMasami Hiramatsu if (arg->name == NULL) 99502b95dadSMasami Hiramatsu return -ENOMEM; 99602b95dadSMasami Hiramatsu } 997146a1439SMasami Hiramatsu return 0; 9987df2f329SMasami Hiramatsu } 9997df2f329SMasami Hiramatsu 10004235b045SMasami Hiramatsu /* Parse perf-probe event command */ 1001146a1439SMasami Hiramatsu int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) 100250656eecSMasami Hiramatsu { 1003e1c01d61SMasami Hiramatsu char **argv; 1004146a1439SMasami Hiramatsu int argc, i, ret = 0; 1005fac13fd5SMasami Hiramatsu 10064235b045SMasami Hiramatsu argv = argv_split(cmd, &argc); 1007146a1439SMasami Hiramatsu if (!argv) { 1008146a1439SMasami Hiramatsu pr_debug("Failed to split arguments.\n"); 1009146a1439SMasami Hiramatsu return -ENOMEM; 1010146a1439SMasami Hiramatsu } 1011146a1439SMasami Hiramatsu if (argc - 1 > MAX_PROBE_ARGS) { 1012146a1439SMasami Hiramatsu semantic_error("Too many probe arguments (%d).\n", argc - 1); 1013146a1439SMasami Hiramatsu ret = -ERANGE; 1014146a1439SMasami Hiramatsu goto out; 1015146a1439SMasami Hiramatsu } 101650656eecSMasami Hiramatsu /* Parse probe point */ 1017146a1439SMasami Hiramatsu ret = parse_perf_probe_point(argv[0], pev); 1018146a1439SMasami Hiramatsu if (ret < 0) 1019146a1439SMasami Hiramatsu goto out; 102050656eecSMasami Hiramatsu 1021e1c01d61SMasami Hiramatsu /* Copy arguments and ensure return probe has no C argument */ 10224235b045SMasami Hiramatsu pev->nargs = argc - 1; 1023e334016fSMasami Hiramatsu pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); 1024e334016fSMasami Hiramatsu if (pev->args == NULL) { 1025e334016fSMasami Hiramatsu ret = -ENOMEM; 1026e334016fSMasami Hiramatsu goto out; 1027e334016fSMasami Hiramatsu } 1028146a1439SMasami Hiramatsu for (i = 0; i < pev->nargs && ret >= 0; i++) { 1029146a1439SMasami Hiramatsu ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]); 1030146a1439SMasami Hiramatsu if (ret >= 0 && 1031146a1439SMasami Hiramatsu is_c_varname(pev->args[i].var) && pev->point.retprobe) { 10324235b045SMasami Hiramatsu semantic_error("You can't specify local variable for" 1033146a1439SMasami Hiramatsu " kretprobe.\n"); 1034146a1439SMasami Hiramatsu ret = -EINVAL; 1035e1c01d61SMasami Hiramatsu } 1036146a1439SMasami Hiramatsu } 1037146a1439SMasami Hiramatsu out: 1038e1c01d61SMasami Hiramatsu argv_free(argv); 1039146a1439SMasami Hiramatsu 1040146a1439SMasami Hiramatsu return ret; 104150656eecSMasami Hiramatsu } 104250656eecSMasami Hiramatsu 10434235b045SMasami Hiramatsu /* Return true if this perf_probe_event requires debuginfo */ 10444235b045SMasami Hiramatsu bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) 10454de189feSMasami Hiramatsu { 10464235b045SMasami Hiramatsu int i; 10474235b045SMasami Hiramatsu 10484235b045SMasami Hiramatsu if (pev->point.file || pev->point.line || pev->point.lazy_line) 10494235b045SMasami Hiramatsu return true; 10504235b045SMasami Hiramatsu 10514235b045SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) 105248481938SMasami Hiramatsu if (is_c_varname(pev->args[i].var)) 10534235b045SMasami Hiramatsu return true; 10544235b045SMasami Hiramatsu 10554235b045SMasami Hiramatsu return false; 10564235b045SMasami Hiramatsu } 10574235b045SMasami Hiramatsu 10580e60836bSSrikar Dronamraju /* Parse probe_events event into struct probe_point */ 10590e60836bSSrikar Dronamraju static int parse_probe_trace_command(const char *cmd, 10600e60836bSSrikar Dronamraju struct probe_trace_event *tev) 10614235b045SMasami Hiramatsu { 10620e60836bSSrikar Dronamraju struct probe_trace_point *tp = &tev->point; 10634de189feSMasami Hiramatsu char pr; 10644de189feSMasami Hiramatsu char *p; 10654de189feSMasami Hiramatsu int ret, i, argc; 10664de189feSMasami Hiramatsu char **argv; 10674de189feSMasami Hiramatsu 10680e60836bSSrikar Dronamraju pr_debug("Parsing probe_events: %s\n", cmd); 10694235b045SMasami Hiramatsu argv = argv_split(cmd, &argc); 1070146a1439SMasami Hiramatsu if (!argv) { 1071146a1439SMasami Hiramatsu pr_debug("Failed to split arguments.\n"); 1072146a1439SMasami Hiramatsu return -ENOMEM; 1073146a1439SMasami Hiramatsu } 1074146a1439SMasami Hiramatsu if (argc < 2) { 1075146a1439SMasami Hiramatsu semantic_error("Too few probe arguments.\n"); 1076146a1439SMasami Hiramatsu ret = -ERANGE; 1077146a1439SMasami Hiramatsu goto out; 1078146a1439SMasami Hiramatsu } 10794de189feSMasami Hiramatsu 10804de189feSMasami Hiramatsu /* Scan event and group name. */ 108193aaa45aSLiming Wang ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", 10824235b045SMasami Hiramatsu &pr, (float *)(void *)&tev->group, 10834235b045SMasami Hiramatsu (float *)(void *)&tev->event); 1084146a1439SMasami Hiramatsu if (ret != 3) { 1085146a1439SMasami Hiramatsu semantic_error("Failed to parse event name: %s\n", argv[0]); 1086146a1439SMasami Hiramatsu ret = -EINVAL; 1087146a1439SMasami Hiramatsu goto out; 1088146a1439SMasami Hiramatsu } 10894235b045SMasami Hiramatsu pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr); 10904de189feSMasami Hiramatsu 10914235b045SMasami Hiramatsu tp->retprobe = (pr == 'r'); 10924de189feSMasami Hiramatsu 1093190b57fcSMasami Hiramatsu /* Scan module name(if there), function name and offset */ 1094190b57fcSMasami Hiramatsu p = strchr(argv[1], ':'); 1095190b57fcSMasami Hiramatsu if (p) { 1096190b57fcSMasami Hiramatsu tp->module = strndup(argv[1], p - argv[1]); 1097190b57fcSMasami Hiramatsu p++; 1098190b57fcSMasami Hiramatsu } else 1099190b57fcSMasami Hiramatsu p = argv[1]; 1100190b57fcSMasami Hiramatsu ret = sscanf(p, "%a[^+]+%lu", (float *)(void *)&tp->symbol, 11014235b045SMasami Hiramatsu &tp->offset); 11024de189feSMasami Hiramatsu if (ret == 1) 11034235b045SMasami Hiramatsu tp->offset = 0; 11044de189feSMasami Hiramatsu 11054235b045SMasami Hiramatsu tev->nargs = argc - 2; 11060e60836bSSrikar Dronamraju tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1107e334016fSMasami Hiramatsu if (tev->args == NULL) { 1108e334016fSMasami Hiramatsu ret = -ENOMEM; 1109e334016fSMasami Hiramatsu goto out; 1110e334016fSMasami Hiramatsu } 11114235b045SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 11124de189feSMasami Hiramatsu p = strchr(argv[i + 2], '='); 11134de189feSMasami Hiramatsu if (p) /* We don't need which register is assigned. */ 11144235b045SMasami Hiramatsu *p++ = '\0'; 11154235b045SMasami Hiramatsu else 11164235b045SMasami Hiramatsu p = argv[i + 2]; 111702b95dadSMasami Hiramatsu tev->args[i].name = strdup(argv[i + 2]); 11184235b045SMasami Hiramatsu /* TODO: parse regs and offset */ 111902b95dadSMasami Hiramatsu tev->args[i].value = strdup(p); 112002b95dadSMasami Hiramatsu if (tev->args[i].name == NULL || tev->args[i].value == NULL) { 112102b95dadSMasami Hiramatsu ret = -ENOMEM; 112202b95dadSMasami Hiramatsu goto out; 112302b95dadSMasami Hiramatsu } 11244de189feSMasami Hiramatsu } 1125146a1439SMasami Hiramatsu ret = 0; 1126146a1439SMasami Hiramatsu out: 11274de189feSMasami Hiramatsu argv_free(argv); 1128146a1439SMasami Hiramatsu return ret; 11294de189feSMasami Hiramatsu } 11304de189feSMasami Hiramatsu 11317df2f329SMasami Hiramatsu /* Compose only probe arg */ 11327df2f329SMasami Hiramatsu int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) 11337df2f329SMasami Hiramatsu { 11347df2f329SMasami Hiramatsu struct perf_probe_arg_field *field = pa->field; 11357df2f329SMasami Hiramatsu int ret; 11367df2f329SMasami Hiramatsu char *tmp = buf; 11377df2f329SMasami Hiramatsu 113848481938SMasami Hiramatsu if (pa->name && pa->var) 113948481938SMasami Hiramatsu ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var); 114048481938SMasami Hiramatsu else 114148481938SMasami Hiramatsu ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var); 11427df2f329SMasami Hiramatsu if (ret <= 0) 11437df2f329SMasami Hiramatsu goto error; 11447df2f329SMasami Hiramatsu tmp += ret; 11457df2f329SMasami Hiramatsu len -= ret; 11467df2f329SMasami Hiramatsu 11477df2f329SMasami Hiramatsu while (field) { 1148b2a3c12bSMasami Hiramatsu if (field->name[0] == '[') 1149b2a3c12bSMasami Hiramatsu ret = e_snprintf(tmp, len, "%s", field->name); 1150b2a3c12bSMasami Hiramatsu else 1151b2a3c12bSMasami Hiramatsu ret = e_snprintf(tmp, len, "%s%s", 1152b2a3c12bSMasami Hiramatsu field->ref ? "->" : ".", field->name); 11537df2f329SMasami Hiramatsu if (ret <= 0) 11547df2f329SMasami Hiramatsu goto error; 11557df2f329SMasami Hiramatsu tmp += ret; 11567df2f329SMasami Hiramatsu len -= ret; 11577df2f329SMasami Hiramatsu field = field->next; 11587df2f329SMasami Hiramatsu } 115911a1ca35SMasami Hiramatsu 116011a1ca35SMasami Hiramatsu if (pa->type) { 116111a1ca35SMasami Hiramatsu ret = e_snprintf(tmp, len, ":%s", pa->type); 116211a1ca35SMasami Hiramatsu if (ret <= 0) 116311a1ca35SMasami Hiramatsu goto error; 116411a1ca35SMasami Hiramatsu tmp += ret; 116511a1ca35SMasami Hiramatsu len -= ret; 116611a1ca35SMasami Hiramatsu } 116711a1ca35SMasami Hiramatsu 11687df2f329SMasami Hiramatsu return tmp - buf; 11697df2f329SMasami Hiramatsu error: 11700e43e5d2SMasami Hiramatsu pr_debug("Failed to synthesize perf probe argument: %s\n", 1171146a1439SMasami Hiramatsu strerror(-ret)); 1172146a1439SMasami Hiramatsu return ret; 11737df2f329SMasami Hiramatsu } 11747df2f329SMasami Hiramatsu 11754235b045SMasami Hiramatsu /* Compose only probe point (not argument) */ 11764235b045SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp) 117750656eecSMasami Hiramatsu { 1178fb1587d8SMasami Hiramatsu char *buf, *tmp; 1179fb1587d8SMasami Hiramatsu char offs[32] = "", line[32] = "", file[32] = ""; 1180fb1587d8SMasami Hiramatsu int ret, len; 118150656eecSMasami Hiramatsu 1182e334016fSMasami Hiramatsu buf = zalloc(MAX_CMDLEN); 1183e334016fSMasami Hiramatsu if (buf == NULL) { 1184e334016fSMasami Hiramatsu ret = -ENOMEM; 1185e334016fSMasami Hiramatsu goto error; 1186e334016fSMasami Hiramatsu } 11874de189feSMasami Hiramatsu if (pp->offset) { 1188fb1587d8SMasami Hiramatsu ret = e_snprintf(offs, 32, "+%lu", pp->offset); 11894de189feSMasami Hiramatsu if (ret <= 0) 11904de189feSMasami Hiramatsu goto error; 11914de189feSMasami Hiramatsu } 11924de189feSMasami Hiramatsu if (pp->line) { 1193fb1587d8SMasami Hiramatsu ret = e_snprintf(line, 32, ":%d", pp->line); 1194fb1587d8SMasami Hiramatsu if (ret <= 0) 1195fb1587d8SMasami Hiramatsu goto error; 1196fb1587d8SMasami Hiramatsu } 1197fb1587d8SMasami Hiramatsu if (pp->file) { 119832ae2adeSFranck Bui-Huu tmp = pp->file; 119932ae2adeSFranck Bui-Huu len = strlen(tmp); 120032ae2adeSFranck Bui-Huu if (len > 30) { 120132ae2adeSFranck Bui-Huu tmp = strchr(pp->file + len - 30, '/'); 120232ae2adeSFranck Bui-Huu tmp = tmp ? tmp + 1 : pp->file + len - 30; 120332ae2adeSFranck Bui-Huu } 120432ae2adeSFranck Bui-Huu ret = e_snprintf(file, 32, "@%s", tmp); 12054de189feSMasami Hiramatsu if (ret <= 0) 12064de189feSMasami Hiramatsu goto error; 12074de189feSMasami Hiramatsu } 12084de189feSMasami Hiramatsu 12094de189feSMasami Hiramatsu if (pp->function) 1210fb1587d8SMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function, 1211fb1587d8SMasami Hiramatsu offs, pp->retprobe ? "%return" : "", line, 1212fb1587d8SMasami Hiramatsu file); 12134de189feSMasami Hiramatsu else 1214fb1587d8SMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line); 12154235b045SMasami Hiramatsu if (ret <= 0) 12164235b045SMasami Hiramatsu goto error; 12174235b045SMasami Hiramatsu 12184235b045SMasami Hiramatsu return buf; 12194235b045SMasami Hiramatsu error: 12200e43e5d2SMasami Hiramatsu pr_debug("Failed to synthesize perf probe point: %s\n", 1221146a1439SMasami Hiramatsu strerror(-ret)); 1222e334016fSMasami Hiramatsu if (buf) 1223146a1439SMasami Hiramatsu free(buf); 1224146a1439SMasami Hiramatsu return NULL; 12254235b045SMasami Hiramatsu } 12264235b045SMasami Hiramatsu 12274235b045SMasami Hiramatsu #if 0 12284235b045SMasami Hiramatsu char *synthesize_perf_probe_command(struct perf_probe_event *pev) 12294235b045SMasami Hiramatsu { 12304235b045SMasami Hiramatsu char *buf; 12314235b045SMasami Hiramatsu int i, len, ret; 12324235b045SMasami Hiramatsu 12334235b045SMasami Hiramatsu buf = synthesize_perf_probe_point(&pev->point); 12344235b045SMasami Hiramatsu if (!buf) 12354235b045SMasami Hiramatsu return NULL; 12364235b045SMasami Hiramatsu 12374235b045SMasami Hiramatsu len = strlen(buf); 12384235b045SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) { 12394235b045SMasami Hiramatsu ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 12404235b045SMasami Hiramatsu pev->args[i].name); 12417ef17aafSMasami Hiramatsu if (ret <= 0) { 12424235b045SMasami Hiramatsu free(buf); 12434235b045SMasami Hiramatsu return NULL; 12447ef17aafSMasami Hiramatsu } 12454235b045SMasami Hiramatsu len += ret; 12467ef17aafSMasami Hiramatsu } 124750656eecSMasami Hiramatsu 12484235b045SMasami Hiramatsu return buf; 12494235b045SMasami Hiramatsu } 12504235b045SMasami Hiramatsu #endif 12514235b045SMasami Hiramatsu 12520e60836bSSrikar Dronamraju static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, 12534235b045SMasami Hiramatsu char **buf, size_t *buflen, 12544235b045SMasami Hiramatsu int depth) 12557ef17aafSMasami Hiramatsu { 12564235b045SMasami Hiramatsu int ret; 12574235b045SMasami Hiramatsu if (ref->next) { 12580e60836bSSrikar Dronamraju depth = __synthesize_probe_trace_arg_ref(ref->next, buf, 12594235b045SMasami Hiramatsu buflen, depth + 1); 12604235b045SMasami Hiramatsu if (depth < 0) 12614235b045SMasami Hiramatsu goto out; 12624235b045SMasami Hiramatsu } 12634235b045SMasami Hiramatsu 12644235b045SMasami Hiramatsu ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset); 12654235b045SMasami Hiramatsu if (ret < 0) 12664235b045SMasami Hiramatsu depth = ret; 12674235b045SMasami Hiramatsu else { 12684235b045SMasami Hiramatsu *buf += ret; 12694235b045SMasami Hiramatsu *buflen -= ret; 12704235b045SMasami Hiramatsu } 12714235b045SMasami Hiramatsu out: 12724235b045SMasami Hiramatsu return depth; 12734235b045SMasami Hiramatsu 12744235b045SMasami Hiramatsu } 12754235b045SMasami Hiramatsu 12760e60836bSSrikar Dronamraju static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, 12774235b045SMasami Hiramatsu char *buf, size_t buflen) 12784235b045SMasami Hiramatsu { 12790e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref = arg->ref; 12804235b045SMasami Hiramatsu int ret, depth = 0; 12814235b045SMasami Hiramatsu char *tmp = buf; 12824235b045SMasami Hiramatsu 12834235b045SMasami Hiramatsu /* Argument name or separator */ 12844235b045SMasami Hiramatsu if (arg->name) 12854235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, " %s=", arg->name); 12864235b045SMasami Hiramatsu else 12874235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, " "); 12884235b045SMasami Hiramatsu if (ret < 0) 12894235b045SMasami Hiramatsu return ret; 12904235b045SMasami Hiramatsu buf += ret; 12914235b045SMasami Hiramatsu buflen -= ret; 12924235b045SMasami Hiramatsu 1293b7dcb857SMasami Hiramatsu /* Special case: @XXX */ 1294b7dcb857SMasami Hiramatsu if (arg->value[0] == '@' && arg->ref) 1295b7dcb857SMasami Hiramatsu ref = ref->next; 1296b7dcb857SMasami Hiramatsu 12974235b045SMasami Hiramatsu /* Dereferencing arguments */ 1298b7dcb857SMasami Hiramatsu if (ref) { 12990e60836bSSrikar Dronamraju depth = __synthesize_probe_trace_arg_ref(ref, &buf, 13004235b045SMasami Hiramatsu &buflen, 1); 13014235b045SMasami Hiramatsu if (depth < 0) 13024235b045SMasami Hiramatsu return depth; 13034235b045SMasami Hiramatsu } 13044235b045SMasami Hiramatsu 13054235b045SMasami Hiramatsu /* Print argument value */ 1306b7dcb857SMasami Hiramatsu if (arg->value[0] == '@' && arg->ref) 1307b7dcb857SMasami Hiramatsu ret = e_snprintf(buf, buflen, "%s%+ld", arg->value, 1308b7dcb857SMasami Hiramatsu arg->ref->offset); 1309b7dcb857SMasami Hiramatsu else 13104235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, "%s", arg->value); 13114235b045SMasami Hiramatsu if (ret < 0) 13124235b045SMasami Hiramatsu return ret; 13134235b045SMasami Hiramatsu buf += ret; 13144235b045SMasami Hiramatsu buflen -= ret; 13154235b045SMasami Hiramatsu 13164235b045SMasami Hiramatsu /* Closing */ 13174235b045SMasami Hiramatsu while (depth--) { 13184235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, ")"); 13194235b045SMasami Hiramatsu if (ret < 0) 13204235b045SMasami Hiramatsu return ret; 13214235b045SMasami Hiramatsu buf += ret; 13224235b045SMasami Hiramatsu buflen -= ret; 13234235b045SMasami Hiramatsu } 13244984912eSMasami Hiramatsu /* Print argument type */ 13254984912eSMasami Hiramatsu if (arg->type) { 13264984912eSMasami Hiramatsu ret = e_snprintf(buf, buflen, ":%s", arg->type); 13274984912eSMasami Hiramatsu if (ret <= 0) 13284984912eSMasami Hiramatsu return ret; 13294984912eSMasami Hiramatsu buf += ret; 13304984912eSMasami Hiramatsu } 13314235b045SMasami Hiramatsu 13324235b045SMasami Hiramatsu return buf - tmp; 13334235b045SMasami Hiramatsu } 13344235b045SMasami Hiramatsu 13350e60836bSSrikar Dronamraju char *synthesize_probe_trace_command(struct probe_trace_event *tev) 13364235b045SMasami Hiramatsu { 13370e60836bSSrikar Dronamraju struct probe_trace_point *tp = &tev->point; 13387ef17aafSMasami Hiramatsu char *buf; 13397ef17aafSMasami Hiramatsu int i, len, ret; 13407ef17aafSMasami Hiramatsu 1341e334016fSMasami Hiramatsu buf = zalloc(MAX_CMDLEN); 1342e334016fSMasami Hiramatsu if (buf == NULL) 1343e334016fSMasami Hiramatsu return NULL; 1344e334016fSMasami Hiramatsu 1345190b57fcSMasami Hiramatsu len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", 13464235b045SMasami Hiramatsu tp->retprobe ? 'r' : 'p', 13474235b045SMasami Hiramatsu tev->group, tev->event, 1348190b57fcSMasami Hiramatsu tp->module ?: "", tp->module ? ":" : "", 13494235b045SMasami Hiramatsu tp->symbol, tp->offset); 13504235b045SMasami Hiramatsu if (len <= 0) 13514235b045SMasami Hiramatsu goto error; 13527ef17aafSMasami Hiramatsu 13534235b045SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 13540e60836bSSrikar Dronamraju ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, 13554235b045SMasami Hiramatsu MAX_CMDLEN - len); 13564de189feSMasami Hiramatsu if (ret <= 0) 135750656eecSMasami Hiramatsu goto error; 135850656eecSMasami Hiramatsu len += ret; 135950656eecSMasami Hiramatsu } 136050656eecSMasami Hiramatsu 13614235b045SMasami Hiramatsu return buf; 136250656eecSMasami Hiramatsu error: 13634235b045SMasami Hiramatsu free(buf); 13644235b045SMasami Hiramatsu return NULL; 136550656eecSMasami Hiramatsu } 136650656eecSMasami Hiramatsu 13670e60836bSSrikar Dronamraju static int convert_to_perf_probe_event(struct probe_trace_event *tev, 13684235b045SMasami Hiramatsu struct perf_probe_event *pev) 13694de189feSMasami Hiramatsu { 137002b95dadSMasami Hiramatsu char buf[64] = ""; 1371146a1439SMasami Hiramatsu int i, ret; 13724de189feSMasami Hiramatsu 13734b4da7f7SMasami Hiramatsu /* Convert event/group name */ 137402b95dadSMasami Hiramatsu pev->event = strdup(tev->event); 137502b95dadSMasami Hiramatsu pev->group = strdup(tev->group); 137602b95dadSMasami Hiramatsu if (pev->event == NULL || pev->group == NULL) 137702b95dadSMasami Hiramatsu return -ENOMEM; 1378fb1587d8SMasami Hiramatsu 13794b4da7f7SMasami Hiramatsu /* Convert trace_point to probe_point */ 13800e60836bSSrikar Dronamraju ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); 1381146a1439SMasami Hiramatsu if (ret < 0) 1382146a1439SMasami Hiramatsu return ret; 13834b4da7f7SMasami Hiramatsu 13844235b045SMasami Hiramatsu /* Convert trace_arg to probe_arg */ 13854235b045SMasami Hiramatsu pev->nargs = tev->nargs; 1386e334016fSMasami Hiramatsu pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); 1387e334016fSMasami Hiramatsu if (pev->args == NULL) 1388e334016fSMasami Hiramatsu return -ENOMEM; 138902b95dadSMasami Hiramatsu for (i = 0; i < tev->nargs && ret >= 0; i++) { 13904235b045SMasami Hiramatsu if (tev->args[i].name) 139102b95dadSMasami Hiramatsu pev->args[i].name = strdup(tev->args[i].name); 13924235b045SMasami Hiramatsu else { 13930e60836bSSrikar Dronamraju ret = synthesize_probe_trace_arg(&tev->args[i], 1394146a1439SMasami Hiramatsu buf, 64); 139502b95dadSMasami Hiramatsu pev->args[i].name = strdup(buf); 139602b95dadSMasami Hiramatsu } 139702b95dadSMasami Hiramatsu if (pev->args[i].name == NULL && ret >= 0) 139802b95dadSMasami Hiramatsu ret = -ENOMEM; 13994de189feSMasami Hiramatsu } 1400146a1439SMasami Hiramatsu 1401146a1439SMasami Hiramatsu if (ret < 0) 1402146a1439SMasami Hiramatsu clear_perf_probe_event(pev); 1403146a1439SMasami Hiramatsu 1404146a1439SMasami Hiramatsu return ret; 14054235b045SMasami Hiramatsu } 14064de189feSMasami Hiramatsu 14074235b045SMasami Hiramatsu void clear_perf_probe_event(struct perf_probe_event *pev) 14084235b045SMasami Hiramatsu { 14094235b045SMasami Hiramatsu struct perf_probe_point *pp = &pev->point; 14107df2f329SMasami Hiramatsu struct perf_probe_arg_field *field, *next; 14114235b045SMasami Hiramatsu int i; 14124de189feSMasami Hiramatsu 14134235b045SMasami Hiramatsu if (pev->event) 14144235b045SMasami Hiramatsu free(pev->event); 14154235b045SMasami Hiramatsu if (pev->group) 14164235b045SMasami Hiramatsu free(pev->group); 14174235b045SMasami Hiramatsu if (pp->file) 14184235b045SMasami Hiramatsu free(pp->file); 14194235b045SMasami Hiramatsu if (pp->function) 14204235b045SMasami Hiramatsu free(pp->function); 14214235b045SMasami Hiramatsu if (pp->lazy_line) 14224235b045SMasami Hiramatsu free(pp->lazy_line); 14237df2f329SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) { 14244235b045SMasami Hiramatsu if (pev->args[i].name) 14254235b045SMasami Hiramatsu free(pev->args[i].name); 142648481938SMasami Hiramatsu if (pev->args[i].var) 142748481938SMasami Hiramatsu free(pev->args[i].var); 142811a1ca35SMasami Hiramatsu if (pev->args[i].type) 142911a1ca35SMasami Hiramatsu free(pev->args[i].type); 14307df2f329SMasami Hiramatsu field = pev->args[i].field; 14317df2f329SMasami Hiramatsu while (field) { 14327df2f329SMasami Hiramatsu next = field->next; 14337df2f329SMasami Hiramatsu if (field->name) 14347df2f329SMasami Hiramatsu free(field->name); 14357df2f329SMasami Hiramatsu free(field); 14367df2f329SMasami Hiramatsu field = next; 14377df2f329SMasami Hiramatsu } 14387df2f329SMasami Hiramatsu } 14394235b045SMasami Hiramatsu if (pev->args) 14404235b045SMasami Hiramatsu free(pev->args); 14414235b045SMasami Hiramatsu memset(pev, 0, sizeof(*pev)); 14424235b045SMasami Hiramatsu } 14434235b045SMasami Hiramatsu 14440e60836bSSrikar Dronamraju static void clear_probe_trace_event(struct probe_trace_event *tev) 14454235b045SMasami Hiramatsu { 14460e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref, *next; 14474235b045SMasami Hiramatsu int i; 14484235b045SMasami Hiramatsu 14494235b045SMasami Hiramatsu if (tev->event) 14504235b045SMasami Hiramatsu free(tev->event); 14514235b045SMasami Hiramatsu if (tev->group) 14524235b045SMasami Hiramatsu free(tev->group); 14534235b045SMasami Hiramatsu if (tev->point.symbol) 14544235b045SMasami Hiramatsu free(tev->point.symbol); 1455190b57fcSMasami Hiramatsu if (tev->point.module) 1456190b57fcSMasami Hiramatsu free(tev->point.module); 14574235b045SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 14584235b045SMasami Hiramatsu if (tev->args[i].name) 14594235b045SMasami Hiramatsu free(tev->args[i].name); 14604235b045SMasami Hiramatsu if (tev->args[i].value) 14614235b045SMasami Hiramatsu free(tev->args[i].value); 14624984912eSMasami Hiramatsu if (tev->args[i].type) 14634984912eSMasami Hiramatsu free(tev->args[i].type); 14644235b045SMasami Hiramatsu ref = tev->args[i].ref; 14654235b045SMasami Hiramatsu while (ref) { 14664235b045SMasami Hiramatsu next = ref->next; 14674235b045SMasami Hiramatsu free(ref); 14684235b045SMasami Hiramatsu ref = next; 14694235b045SMasami Hiramatsu } 14704235b045SMasami Hiramatsu } 14714235b045SMasami Hiramatsu if (tev->args) 14724235b045SMasami Hiramatsu free(tev->args); 14734235b045SMasami Hiramatsu memset(tev, 0, sizeof(*tev)); 14744de189feSMasami Hiramatsu } 14754de189feSMasami Hiramatsu 1476f4d7da49SMasami Hiramatsu static int open_kprobe_events(bool readwrite) 14774de189feSMasami Hiramatsu { 14784de189feSMasami Hiramatsu char buf[PATH_MAX]; 14797ca5989dSMasami Hiramatsu const char *__debugfs; 14804de189feSMasami Hiramatsu int ret; 14814de189feSMasami Hiramatsu 14827ca5989dSMasami Hiramatsu __debugfs = debugfs_find_mountpoint(); 14837ca5989dSMasami Hiramatsu if (__debugfs == NULL) { 14847ca5989dSMasami Hiramatsu pr_warning("Debugfs is not mounted.\n"); 14857ca5989dSMasami Hiramatsu return -ENOENT; 14867ca5989dSMasami Hiramatsu } 14877ca5989dSMasami Hiramatsu 14887ca5989dSMasami Hiramatsu ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs); 1489146a1439SMasami Hiramatsu if (ret >= 0) { 14907ca5989dSMasami Hiramatsu pr_debug("Opening %s write=%d\n", buf, readwrite); 1491f4d7da49SMasami Hiramatsu if (readwrite && !probe_event_dry_run) 1492f4d7da49SMasami Hiramatsu ret = open(buf, O_RDWR, O_APPEND); 1493f4d7da49SMasami Hiramatsu else 1494f4d7da49SMasami Hiramatsu ret = open(buf, O_RDONLY, 0); 1495146a1439SMasami Hiramatsu } 1496f4d7da49SMasami Hiramatsu 14974de189feSMasami Hiramatsu if (ret < 0) { 14984de189feSMasami Hiramatsu if (errno == ENOENT) 1499146a1439SMasami Hiramatsu pr_warning("kprobe_events file does not exist - please" 1500146a1439SMasami Hiramatsu " rebuild kernel with CONFIG_KPROBE_EVENT.\n"); 15014de189feSMasami Hiramatsu else 1502146a1439SMasami Hiramatsu pr_warning("Failed to open kprobe_events file: %s\n", 15034de189feSMasami Hiramatsu strerror(errno)); 15044de189feSMasami Hiramatsu } 15054de189feSMasami Hiramatsu return ret; 15064de189feSMasami Hiramatsu } 15074de189feSMasami Hiramatsu 15084de189feSMasami Hiramatsu /* Get raw string list of current kprobe_events */ 15090e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_command_rawlist(int fd) 15104de189feSMasami Hiramatsu { 15114de189feSMasami Hiramatsu int ret, idx; 15124de189feSMasami Hiramatsu FILE *fp; 15134de189feSMasami Hiramatsu char buf[MAX_CMDLEN]; 15144de189feSMasami Hiramatsu char *p; 15154de189feSMasami Hiramatsu struct strlist *sl; 15164de189feSMasami Hiramatsu 15174de189feSMasami Hiramatsu sl = strlist__new(true, NULL); 15184de189feSMasami Hiramatsu 15194de189feSMasami Hiramatsu fp = fdopen(dup(fd), "r"); 15204de189feSMasami Hiramatsu while (!feof(fp)) { 15214de189feSMasami Hiramatsu p = fgets(buf, MAX_CMDLEN, fp); 15224de189feSMasami Hiramatsu if (!p) 15234de189feSMasami Hiramatsu break; 15244de189feSMasami Hiramatsu 15254de189feSMasami Hiramatsu idx = strlen(p) - 1; 15264de189feSMasami Hiramatsu if (p[idx] == '\n') 15274de189feSMasami Hiramatsu p[idx] = '\0'; 15284de189feSMasami Hiramatsu ret = strlist__add(sl, buf); 1529146a1439SMasami Hiramatsu if (ret < 0) { 1530146a1439SMasami Hiramatsu pr_debug("strlist__add failed: %s\n", strerror(-ret)); 1531146a1439SMasami Hiramatsu strlist__delete(sl); 1532146a1439SMasami Hiramatsu return NULL; 1533146a1439SMasami Hiramatsu } 15344de189feSMasami Hiramatsu } 15354de189feSMasami Hiramatsu fclose(fp); 15364de189feSMasami Hiramatsu 15374de189feSMasami Hiramatsu return sl; 15384de189feSMasami Hiramatsu } 15394de189feSMasami Hiramatsu 1540278498d4SMasami Hiramatsu /* Show an event */ 1541146a1439SMasami Hiramatsu static int show_perf_probe_event(struct perf_probe_event *pev) 1542278498d4SMasami Hiramatsu { 15437e990a51SMasami Hiramatsu int i, ret; 1544278498d4SMasami Hiramatsu char buf[128]; 15454235b045SMasami Hiramatsu char *place; 1546278498d4SMasami Hiramatsu 15474235b045SMasami Hiramatsu /* Synthesize only event probe point */ 15484235b045SMasami Hiramatsu place = synthesize_perf_probe_point(&pev->point); 1549146a1439SMasami Hiramatsu if (!place) 1550146a1439SMasami Hiramatsu return -EINVAL; 15514235b045SMasami Hiramatsu 15524235b045SMasami Hiramatsu ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); 15537e990a51SMasami Hiramatsu if (ret < 0) 1554146a1439SMasami Hiramatsu return ret; 1555146a1439SMasami Hiramatsu 1556fb1587d8SMasami Hiramatsu printf(" %-20s (on %s", buf, place); 1557278498d4SMasami Hiramatsu 15584235b045SMasami Hiramatsu if (pev->nargs > 0) { 1559278498d4SMasami Hiramatsu printf(" with"); 15607df2f329SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) { 1561146a1439SMasami Hiramatsu ret = synthesize_perf_probe_arg(&pev->args[i], 1562146a1439SMasami Hiramatsu buf, 128); 1563146a1439SMasami Hiramatsu if (ret < 0) 1564146a1439SMasami Hiramatsu break; 15657df2f329SMasami Hiramatsu printf(" %s", buf); 15667df2f329SMasami Hiramatsu } 1567278498d4SMasami Hiramatsu } 1568278498d4SMasami Hiramatsu printf(")\n"); 15694235b045SMasami Hiramatsu free(place); 1570146a1439SMasami Hiramatsu return ret; 1571278498d4SMasami Hiramatsu } 1572278498d4SMasami Hiramatsu 15734de189feSMasami Hiramatsu /* List up current perf-probe events */ 1574146a1439SMasami Hiramatsu int show_perf_probe_events(void) 15754de189feSMasami Hiramatsu { 1576146a1439SMasami Hiramatsu int fd, ret; 15770e60836bSSrikar Dronamraju struct probe_trace_event tev; 15784235b045SMasami Hiramatsu struct perf_probe_event pev; 15794de189feSMasami Hiramatsu struct strlist *rawlist; 15804de189feSMasami Hiramatsu struct str_node *ent; 15814de189feSMasami Hiramatsu 158272041334SMasami Hiramatsu setup_pager(); 1583146a1439SMasami Hiramatsu ret = init_vmlinux(); 1584146a1439SMasami Hiramatsu if (ret < 0) 1585146a1439SMasami Hiramatsu return ret; 15864235b045SMasami Hiramatsu 15874235b045SMasami Hiramatsu memset(&tev, 0, sizeof(tev)); 15884235b045SMasami Hiramatsu memset(&pev, 0, sizeof(pev)); 158972041334SMasami Hiramatsu 1590f4d7da49SMasami Hiramatsu fd = open_kprobe_events(false); 1591146a1439SMasami Hiramatsu if (fd < 0) 1592146a1439SMasami Hiramatsu return fd; 1593146a1439SMasami Hiramatsu 15940e60836bSSrikar Dronamraju rawlist = get_probe_trace_command_rawlist(fd); 15954de189feSMasami Hiramatsu close(fd); 1596146a1439SMasami Hiramatsu if (!rawlist) 1597146a1439SMasami Hiramatsu return -ENOENT; 15984de189feSMasami Hiramatsu 1599adf365f4SMasami Hiramatsu strlist__for_each(ent, rawlist) { 16000e60836bSSrikar Dronamraju ret = parse_probe_trace_command(ent->s, &tev); 1601146a1439SMasami Hiramatsu if (ret >= 0) { 1602146a1439SMasami Hiramatsu ret = convert_to_perf_probe_event(&tev, &pev); 1603146a1439SMasami Hiramatsu if (ret >= 0) 1604146a1439SMasami Hiramatsu ret = show_perf_probe_event(&pev); 1605146a1439SMasami Hiramatsu } 16064235b045SMasami Hiramatsu clear_perf_probe_event(&pev); 16070e60836bSSrikar Dronamraju clear_probe_trace_event(&tev); 1608146a1439SMasami Hiramatsu if (ret < 0) 1609146a1439SMasami Hiramatsu break; 16104de189feSMasami Hiramatsu } 16114de189feSMasami Hiramatsu strlist__delete(rawlist); 1612146a1439SMasami Hiramatsu 1613146a1439SMasami Hiramatsu return ret; 16144de189feSMasami Hiramatsu } 16154de189feSMasami Hiramatsu 1616b498ce1fSMasami Hiramatsu /* Get current perf-probe event names */ 16170e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_event_names(int fd, bool include_group) 1618b498ce1fSMasami Hiramatsu { 1619fa28244dSMasami Hiramatsu char buf[128]; 1620b498ce1fSMasami Hiramatsu struct strlist *sl, *rawlist; 1621b498ce1fSMasami Hiramatsu struct str_node *ent; 16220e60836bSSrikar Dronamraju struct probe_trace_event tev; 1623146a1439SMasami Hiramatsu int ret = 0; 1624b498ce1fSMasami Hiramatsu 16254235b045SMasami Hiramatsu memset(&tev, 0, sizeof(tev)); 16260e60836bSSrikar Dronamraju rawlist = get_probe_trace_command_rawlist(fd); 1627e1d2017bSMasami Hiramatsu sl = strlist__new(true, NULL); 1628adf365f4SMasami Hiramatsu strlist__for_each(ent, rawlist) { 16290e60836bSSrikar Dronamraju ret = parse_probe_trace_command(ent->s, &tev); 1630146a1439SMasami Hiramatsu if (ret < 0) 1631146a1439SMasami Hiramatsu break; 1632fa28244dSMasami Hiramatsu if (include_group) { 1633146a1439SMasami Hiramatsu ret = e_snprintf(buf, 128, "%s:%s", tev.group, 1634146a1439SMasami Hiramatsu tev.event); 1635146a1439SMasami Hiramatsu if (ret >= 0) 1636146a1439SMasami Hiramatsu ret = strlist__add(sl, buf); 1637fa28244dSMasami Hiramatsu } else 1638146a1439SMasami Hiramatsu ret = strlist__add(sl, tev.event); 16390e60836bSSrikar Dronamraju clear_probe_trace_event(&tev); 1640146a1439SMasami Hiramatsu if (ret < 0) 1641146a1439SMasami Hiramatsu break; 1642b498ce1fSMasami Hiramatsu } 1643b498ce1fSMasami Hiramatsu strlist__delete(rawlist); 1644b498ce1fSMasami Hiramatsu 1645146a1439SMasami Hiramatsu if (ret < 0) { 1646146a1439SMasami Hiramatsu strlist__delete(sl); 1647146a1439SMasami Hiramatsu return NULL; 1648146a1439SMasami Hiramatsu } 1649b498ce1fSMasami Hiramatsu return sl; 1650b498ce1fSMasami Hiramatsu } 1651b498ce1fSMasami Hiramatsu 16520e60836bSSrikar Dronamraju static int write_probe_trace_event(int fd, struct probe_trace_event *tev) 165350656eecSMasami Hiramatsu { 16546eca8cc3SFrederic Weisbecker int ret = 0; 16550e60836bSSrikar Dronamraju char *buf = synthesize_probe_trace_command(tev); 165650656eecSMasami Hiramatsu 1657146a1439SMasami Hiramatsu if (!buf) { 16580e60836bSSrikar Dronamraju pr_debug("Failed to synthesize probe trace event.\n"); 1659146a1439SMasami Hiramatsu return -EINVAL; 1660146a1439SMasami Hiramatsu } 1661146a1439SMasami Hiramatsu 1662fa28244dSMasami Hiramatsu pr_debug("Writing event: %s\n", buf); 1663f4d7da49SMasami Hiramatsu if (!probe_event_dry_run) { 166450656eecSMasami Hiramatsu ret = write(fd, buf, strlen(buf)); 166550656eecSMasami Hiramatsu if (ret <= 0) 1666146a1439SMasami Hiramatsu pr_warning("Failed to write event: %s\n", 1667146a1439SMasami Hiramatsu strerror(errno)); 166850656eecSMasami Hiramatsu } 16694235b045SMasami Hiramatsu free(buf); 1670146a1439SMasami Hiramatsu return ret; 1671f4d7da49SMasami Hiramatsu } 167250656eecSMasami Hiramatsu 1673146a1439SMasami Hiramatsu static int get_new_event_name(char *buf, size_t len, const char *base, 1674d761b08bSMasami Hiramatsu struct strlist *namelist, bool allow_suffix) 1675b498ce1fSMasami Hiramatsu { 1676b498ce1fSMasami Hiramatsu int i, ret; 167717f88fcdSMasami Hiramatsu 167817f88fcdSMasami Hiramatsu /* Try no suffix */ 167917f88fcdSMasami Hiramatsu ret = e_snprintf(buf, len, "%s", base); 1680146a1439SMasami Hiramatsu if (ret < 0) { 1681146a1439SMasami Hiramatsu pr_debug("snprintf() failed: %s\n", strerror(-ret)); 1682146a1439SMasami Hiramatsu return ret; 1683146a1439SMasami Hiramatsu } 168417f88fcdSMasami Hiramatsu if (!strlist__has_entry(namelist, buf)) 1685146a1439SMasami Hiramatsu return 0; 168617f88fcdSMasami Hiramatsu 1687d761b08bSMasami Hiramatsu if (!allow_suffix) { 1688d761b08bSMasami Hiramatsu pr_warning("Error: event \"%s\" already exists. " 1689d761b08bSMasami Hiramatsu "(Use -f to force duplicates.)\n", base); 1690146a1439SMasami Hiramatsu return -EEXIST; 1691d761b08bSMasami Hiramatsu } 1692d761b08bSMasami Hiramatsu 169317f88fcdSMasami Hiramatsu /* Try to add suffix */ 169417f88fcdSMasami Hiramatsu for (i = 1; i < MAX_EVENT_INDEX; i++) { 1695b498ce1fSMasami Hiramatsu ret = e_snprintf(buf, len, "%s_%d", base, i); 1696146a1439SMasami Hiramatsu if (ret < 0) { 1697146a1439SMasami Hiramatsu pr_debug("snprintf() failed: %s\n", strerror(-ret)); 1698146a1439SMasami Hiramatsu return ret; 1699146a1439SMasami Hiramatsu } 1700b498ce1fSMasami Hiramatsu if (!strlist__has_entry(namelist, buf)) 1701b498ce1fSMasami Hiramatsu break; 1702b498ce1fSMasami Hiramatsu } 1703146a1439SMasami Hiramatsu if (i == MAX_EVENT_INDEX) { 1704146a1439SMasami Hiramatsu pr_warning("Too many events are on the same function.\n"); 1705146a1439SMasami Hiramatsu ret = -ERANGE; 1706b498ce1fSMasami Hiramatsu } 1707b498ce1fSMasami Hiramatsu 1708146a1439SMasami Hiramatsu return ret; 1709146a1439SMasami Hiramatsu } 1710146a1439SMasami Hiramatsu 17110e60836bSSrikar Dronamraju static int __add_probe_trace_events(struct perf_probe_event *pev, 17120e60836bSSrikar Dronamraju struct probe_trace_event *tevs, 17134235b045SMasami Hiramatsu int ntevs, bool allow_suffix) 171450656eecSMasami Hiramatsu { 1715146a1439SMasami Hiramatsu int i, fd, ret; 17160e60836bSSrikar Dronamraju struct probe_trace_event *tev = NULL; 17174235b045SMasami Hiramatsu char buf[64]; 17184235b045SMasami Hiramatsu const char *event, *group; 1719b498ce1fSMasami Hiramatsu struct strlist *namelist; 172050656eecSMasami Hiramatsu 1721f4d7da49SMasami Hiramatsu fd = open_kprobe_events(true); 1722146a1439SMasami Hiramatsu if (fd < 0) 1723146a1439SMasami Hiramatsu return fd; 1724b498ce1fSMasami Hiramatsu /* Get current event names */ 17250e60836bSSrikar Dronamraju namelist = get_probe_trace_event_names(fd, false); 1726146a1439SMasami Hiramatsu if (!namelist) { 1727146a1439SMasami Hiramatsu pr_debug("Failed to get current event list.\n"); 1728146a1439SMasami Hiramatsu return -EIO; 1729146a1439SMasami Hiramatsu } 173050656eecSMasami Hiramatsu 1731146a1439SMasami Hiramatsu ret = 0; 17324235b045SMasami Hiramatsu printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":"); 173302b95dadSMasami Hiramatsu for (i = 0; i < ntevs; i++) { 17344235b045SMasami Hiramatsu tev = &tevs[i]; 17354235b045SMasami Hiramatsu if (pev->event) 17364235b045SMasami Hiramatsu event = pev->event; 17374235b045SMasami Hiramatsu else 17384235b045SMasami Hiramatsu if (pev->point.function) 17394235b045SMasami Hiramatsu event = pev->point.function; 17404235b045SMasami Hiramatsu else 17414235b045SMasami Hiramatsu event = tev->point.symbol; 17424235b045SMasami Hiramatsu if (pev->group) 17434235b045SMasami Hiramatsu group = pev->group; 17444235b045SMasami Hiramatsu else 17454235b045SMasami Hiramatsu group = PERFPROBE_GROUP; 17464235b045SMasami Hiramatsu 1747b498ce1fSMasami Hiramatsu /* Get an unused new event name */ 1748146a1439SMasami Hiramatsu ret = get_new_event_name(buf, 64, event, 1749146a1439SMasami Hiramatsu namelist, allow_suffix); 1750146a1439SMasami Hiramatsu if (ret < 0) 1751146a1439SMasami Hiramatsu break; 17524235b045SMasami Hiramatsu event = buf; 17534235b045SMasami Hiramatsu 175402b95dadSMasami Hiramatsu tev->event = strdup(event); 175502b95dadSMasami Hiramatsu tev->group = strdup(group); 175602b95dadSMasami Hiramatsu if (tev->event == NULL || tev->group == NULL) { 175702b95dadSMasami Hiramatsu ret = -ENOMEM; 175802b95dadSMasami Hiramatsu break; 175902b95dadSMasami Hiramatsu } 17600e60836bSSrikar Dronamraju ret = write_probe_trace_event(fd, tev); 1761146a1439SMasami Hiramatsu if (ret < 0) 1762146a1439SMasami Hiramatsu break; 1763b498ce1fSMasami Hiramatsu /* Add added event name to namelist */ 1764b498ce1fSMasami Hiramatsu strlist__add(namelist, event); 17654235b045SMasami Hiramatsu 17664235b045SMasami Hiramatsu /* Trick here - save current event/group */ 17674235b045SMasami Hiramatsu event = pev->event; 17684235b045SMasami Hiramatsu group = pev->group; 17694235b045SMasami Hiramatsu pev->event = tev->event; 17704235b045SMasami Hiramatsu pev->group = tev->group; 17714235b045SMasami Hiramatsu show_perf_probe_event(pev); 17724235b045SMasami Hiramatsu /* Trick here - restore current event/group */ 17734235b045SMasami Hiramatsu pev->event = (char *)event; 17744235b045SMasami Hiramatsu pev->group = (char *)group; 17754235b045SMasami Hiramatsu 1776d761b08bSMasami Hiramatsu /* 1777d761b08bSMasami Hiramatsu * Probes after the first probe which comes from same 1778d761b08bSMasami Hiramatsu * user input are always allowed to add suffix, because 1779d761b08bSMasami Hiramatsu * there might be several addresses corresponding to 1780d761b08bSMasami Hiramatsu * one code line. 1781d761b08bSMasami Hiramatsu */ 1782d761b08bSMasami Hiramatsu allow_suffix = true; 178350656eecSMasami Hiramatsu } 1784146a1439SMasami Hiramatsu 1785146a1439SMasami Hiramatsu if (ret >= 0) { 1786a9b495b0SMasami Hiramatsu /* Show how to use the event. */ 1787a9b495b0SMasami Hiramatsu printf("\nYou can now use it on all perf tools, such as:\n\n"); 1788146a1439SMasami Hiramatsu printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, 1789146a1439SMasami Hiramatsu tev->event); 1790146a1439SMasami Hiramatsu } 1791a9b495b0SMasami Hiramatsu 1792e1d2017bSMasami Hiramatsu strlist__delete(namelist); 179350656eecSMasami Hiramatsu close(fd); 1794146a1439SMasami Hiramatsu return ret; 179550656eecSMasami Hiramatsu } 1796fa28244dSMasami Hiramatsu 17970e60836bSSrikar Dronamraju static int convert_to_probe_trace_events(struct perf_probe_event *pev, 17980e60836bSSrikar Dronamraju struct probe_trace_event **tevs, 1799469b9b88SMasami Hiramatsu int max_tevs, const char *module) 1800e0faa8d3SMasami Hiramatsu { 1801e0faa8d3SMasami Hiramatsu struct symbol *sym; 1802e334016fSMasami Hiramatsu int ret = 0, i; 18030e60836bSSrikar Dronamraju struct probe_trace_event *tev; 18044235b045SMasami Hiramatsu 18054b4da7f7SMasami Hiramatsu /* Convert perf_probe_event with debuginfo */ 1806469b9b88SMasami Hiramatsu ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module); 1807e334016fSMasami Hiramatsu if (ret != 0) 1808190b57fcSMasami Hiramatsu return ret; /* Found in debuginfo or got an error */ 1809e0faa8d3SMasami Hiramatsu 18104235b045SMasami Hiramatsu /* Allocate trace event buffer */ 18110e60836bSSrikar Dronamraju tev = *tevs = zalloc(sizeof(struct probe_trace_event)); 1812e334016fSMasami Hiramatsu if (tev == NULL) 1813e334016fSMasami Hiramatsu return -ENOMEM; 1814e0faa8d3SMasami Hiramatsu 18154235b045SMasami Hiramatsu /* Copy parameters */ 181602b95dadSMasami Hiramatsu tev->point.symbol = strdup(pev->point.function); 181702b95dadSMasami Hiramatsu if (tev->point.symbol == NULL) { 181802b95dadSMasami Hiramatsu ret = -ENOMEM; 181902b95dadSMasami Hiramatsu goto error; 182002b95dadSMasami Hiramatsu } 1821ce27a443SJovi Zhang 1822ce27a443SJovi Zhang if (module) { 1823190b57fcSMasami Hiramatsu tev->point.module = strdup(module); 1824190b57fcSMasami Hiramatsu if (tev->point.module == NULL) { 1825190b57fcSMasami Hiramatsu ret = -ENOMEM; 1826190b57fcSMasami Hiramatsu goto error; 1827190b57fcSMasami Hiramatsu } 1828ce27a443SJovi Zhang } 1829ce27a443SJovi Zhang 18304235b045SMasami Hiramatsu tev->point.offset = pev->point.offset; 183104ddd04bSMasami Hiramatsu tev->point.retprobe = pev->point.retprobe; 18324235b045SMasami Hiramatsu tev->nargs = pev->nargs; 18334235b045SMasami Hiramatsu if (tev->nargs) { 18340e60836bSSrikar Dronamraju tev->args = zalloc(sizeof(struct probe_trace_arg) 18354235b045SMasami Hiramatsu * tev->nargs); 1836e334016fSMasami Hiramatsu if (tev->args == NULL) { 183702b95dadSMasami Hiramatsu ret = -ENOMEM; 183802b95dadSMasami Hiramatsu goto error; 1839e334016fSMasami Hiramatsu } 184048481938SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 184102b95dadSMasami Hiramatsu if (pev->args[i].name) { 184202b95dadSMasami Hiramatsu tev->args[i].name = strdup(pev->args[i].name); 184302b95dadSMasami Hiramatsu if (tev->args[i].name == NULL) { 184402b95dadSMasami Hiramatsu ret = -ENOMEM; 184502b95dadSMasami Hiramatsu goto error; 184602b95dadSMasami Hiramatsu } 184702b95dadSMasami Hiramatsu } 184802b95dadSMasami Hiramatsu tev->args[i].value = strdup(pev->args[i].var); 184902b95dadSMasami Hiramatsu if (tev->args[i].value == NULL) { 185002b95dadSMasami Hiramatsu ret = -ENOMEM; 185102b95dadSMasami Hiramatsu goto error; 185202b95dadSMasami Hiramatsu } 185302b95dadSMasami Hiramatsu if (pev->args[i].type) { 185402b95dadSMasami Hiramatsu tev->args[i].type = strdup(pev->args[i].type); 185502b95dadSMasami Hiramatsu if (tev->args[i].type == NULL) { 185602b95dadSMasami Hiramatsu ret = -ENOMEM; 185702b95dadSMasami Hiramatsu goto error; 185802b95dadSMasami Hiramatsu } 185902b95dadSMasami Hiramatsu } 186048481938SMasami Hiramatsu } 1861e0faa8d3SMasami Hiramatsu } 1862e0faa8d3SMasami Hiramatsu 18634235b045SMasami Hiramatsu /* Currently just checking function name from symbol map */ 1864469b9b88SMasami Hiramatsu sym = __find_kernel_function_by_name(tev->point.symbol, NULL); 1865146a1439SMasami Hiramatsu if (!sym) { 1866146a1439SMasami Hiramatsu pr_warning("Kernel symbol \'%s\' not found.\n", 18674235b045SMasami Hiramatsu tev->point.symbol); 186802b95dadSMasami Hiramatsu ret = -ENOENT; 186902b95dadSMasami Hiramatsu goto error; 1870*1c1bc922SPrashanth Nageshappa } else if (tev->point.offset > sym->end - sym->start) { 1871*1c1bc922SPrashanth Nageshappa pr_warning("Offset specified is greater than size of %s\n", 1872*1c1bc922SPrashanth Nageshappa tev->point.symbol); 1873*1c1bc922SPrashanth Nageshappa ret = -ENOENT; 1874*1c1bc922SPrashanth Nageshappa goto error; 1875*1c1bc922SPrashanth Nageshappa 187602b95dadSMasami Hiramatsu } 187702b95dadSMasami Hiramatsu 187802b95dadSMasami Hiramatsu return 1; 187902b95dadSMasami Hiramatsu error: 18800e60836bSSrikar Dronamraju clear_probe_trace_event(tev); 1881e334016fSMasami Hiramatsu free(tev); 1882e334016fSMasami Hiramatsu *tevs = NULL; 1883e334016fSMasami Hiramatsu return ret; 18844235b045SMasami Hiramatsu } 18854235b045SMasami Hiramatsu 18864235b045SMasami Hiramatsu struct __event_package { 18874235b045SMasami Hiramatsu struct perf_probe_event *pev; 18880e60836bSSrikar Dronamraju struct probe_trace_event *tevs; 18894235b045SMasami Hiramatsu int ntevs; 18904235b045SMasami Hiramatsu }; 18914235b045SMasami Hiramatsu 1892146a1439SMasami Hiramatsu int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 1893469b9b88SMasami Hiramatsu int max_tevs, const char *module, bool force_add) 18944235b045SMasami Hiramatsu { 1895146a1439SMasami Hiramatsu int i, j, ret; 18964235b045SMasami Hiramatsu struct __event_package *pkgs; 18974235b045SMasami Hiramatsu 1898e334016fSMasami Hiramatsu pkgs = zalloc(sizeof(struct __event_package) * npevs); 1899e334016fSMasami Hiramatsu if (pkgs == NULL) 1900e334016fSMasami Hiramatsu return -ENOMEM; 19014235b045SMasami Hiramatsu 19024235b045SMasami Hiramatsu /* Init vmlinux path */ 1903146a1439SMasami Hiramatsu ret = init_vmlinux(); 1904449e5b24SMasami Hiramatsu if (ret < 0) { 1905449e5b24SMasami Hiramatsu free(pkgs); 1906146a1439SMasami Hiramatsu return ret; 1907449e5b24SMasami Hiramatsu } 19084235b045SMasami Hiramatsu 19094235b045SMasami Hiramatsu /* Loop 1: convert all events */ 19104235b045SMasami Hiramatsu for (i = 0; i < npevs; i++) { 19114235b045SMasami Hiramatsu pkgs[i].pev = &pevs[i]; 19124235b045SMasami Hiramatsu /* Convert with or without debuginfo */ 19130e60836bSSrikar Dronamraju ret = convert_to_probe_trace_events(pkgs[i].pev, 1914469b9b88SMasami Hiramatsu &pkgs[i].tevs, 1915469b9b88SMasami Hiramatsu max_tevs, 1916469b9b88SMasami Hiramatsu module); 1917146a1439SMasami Hiramatsu if (ret < 0) 1918146a1439SMasami Hiramatsu goto end; 1919146a1439SMasami Hiramatsu pkgs[i].ntevs = ret; 19204235b045SMasami Hiramatsu } 19214235b045SMasami Hiramatsu 19224235b045SMasami Hiramatsu /* Loop 2: add all events */ 19238635bf6eSArnaldo Carvalho de Melo for (i = 0; i < npevs; i++) { 19240e60836bSSrikar Dronamraju ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, 19254235b045SMasami Hiramatsu pkgs[i].ntevs, force_add); 1926fbee632dSArnaldo Carvalho de Melo if (ret < 0) 1927fbee632dSArnaldo Carvalho de Melo break; 1928fbee632dSArnaldo Carvalho de Melo } 1929146a1439SMasami Hiramatsu end: 1930449e5b24SMasami Hiramatsu /* Loop 3: cleanup and free trace events */ 1931449e5b24SMasami Hiramatsu for (i = 0; i < npevs; i++) { 1932146a1439SMasami Hiramatsu for (j = 0; j < pkgs[i].ntevs; j++) 19330e60836bSSrikar Dronamraju clear_probe_trace_event(&pkgs[i].tevs[j]); 1934449e5b24SMasami Hiramatsu free(pkgs[i].tevs); 1935449e5b24SMasami Hiramatsu } 1936449e5b24SMasami Hiramatsu free(pkgs); 1937146a1439SMasami Hiramatsu 1938146a1439SMasami Hiramatsu return ret; 1939e0faa8d3SMasami Hiramatsu } 1940e0faa8d3SMasami Hiramatsu 19410e60836bSSrikar Dronamraju static int __del_trace_probe_event(int fd, struct str_node *ent) 1942bbbb521bSMasami Hiramatsu { 1943bbbb521bSMasami Hiramatsu char *p; 1944bbbb521bSMasami Hiramatsu char buf[128]; 19454235b045SMasami Hiramatsu int ret; 1946bbbb521bSMasami Hiramatsu 19470e60836bSSrikar Dronamraju /* Convert from perf-probe event to trace-probe event */ 1948146a1439SMasami Hiramatsu ret = e_snprintf(buf, 128, "-:%s", ent->s); 1949146a1439SMasami Hiramatsu if (ret < 0) 1950146a1439SMasami Hiramatsu goto error; 1951146a1439SMasami Hiramatsu 1952bbbb521bSMasami Hiramatsu p = strchr(buf + 2, ':'); 1953146a1439SMasami Hiramatsu if (!p) { 1954146a1439SMasami Hiramatsu pr_debug("Internal error: %s should have ':' but not.\n", 1955146a1439SMasami Hiramatsu ent->s); 1956146a1439SMasami Hiramatsu ret = -ENOTSUP; 1957146a1439SMasami Hiramatsu goto error; 1958146a1439SMasami Hiramatsu } 1959bbbb521bSMasami Hiramatsu *p = '/'; 1960bbbb521bSMasami Hiramatsu 19614235b045SMasami Hiramatsu pr_debug("Writing event: %s\n", buf); 19624235b045SMasami Hiramatsu ret = write(fd, buf, strlen(buf)); 196344a56040SMasami Hiramatsu if (ret < 0) { 196444a56040SMasami Hiramatsu ret = -errno; 1965146a1439SMasami Hiramatsu goto error; 196644a56040SMasami Hiramatsu } 1967146a1439SMasami Hiramatsu 1968bbbb521bSMasami Hiramatsu printf("Remove event: %s\n", ent->s); 1969146a1439SMasami Hiramatsu return 0; 1970146a1439SMasami Hiramatsu error: 1971146a1439SMasami Hiramatsu pr_warning("Failed to delete event: %s\n", strerror(-ret)); 1972146a1439SMasami Hiramatsu return ret; 1973bbbb521bSMasami Hiramatsu } 1974bbbb521bSMasami Hiramatsu 19750e60836bSSrikar Dronamraju static int del_trace_probe_event(int fd, const char *group, 1976fa28244dSMasami Hiramatsu const char *event, struct strlist *namelist) 1977fa28244dSMasami Hiramatsu { 1978fa28244dSMasami Hiramatsu char buf[128]; 1979bbbb521bSMasami Hiramatsu struct str_node *ent, *n; 1980146a1439SMasami Hiramatsu int found = 0, ret = 0; 1981fa28244dSMasami Hiramatsu 1982146a1439SMasami Hiramatsu ret = e_snprintf(buf, 128, "%s:%s", group, event); 1983146a1439SMasami Hiramatsu if (ret < 0) { 19840e43e5d2SMasami Hiramatsu pr_err("Failed to copy event.\n"); 1985146a1439SMasami Hiramatsu return ret; 1986146a1439SMasami Hiramatsu } 1987fa28244dSMasami Hiramatsu 1988bbbb521bSMasami Hiramatsu if (strpbrk(buf, "*?")) { /* Glob-exp */ 1989bbbb521bSMasami Hiramatsu strlist__for_each_safe(ent, n, namelist) 1990bbbb521bSMasami Hiramatsu if (strglobmatch(ent->s, buf)) { 1991bbbb521bSMasami Hiramatsu found++; 19920e60836bSSrikar Dronamraju ret = __del_trace_probe_event(fd, ent); 1993146a1439SMasami Hiramatsu if (ret < 0) 1994146a1439SMasami Hiramatsu break; 19953e340590SMasami Hiramatsu strlist__remove(namelist, ent); 1996fa28244dSMasami Hiramatsu } 1997bbbb521bSMasami Hiramatsu } else { 1998bbbb521bSMasami Hiramatsu ent = strlist__find(namelist, buf); 1999bbbb521bSMasami Hiramatsu if (ent) { 2000bbbb521bSMasami Hiramatsu found++; 20010e60836bSSrikar Dronamraju ret = __del_trace_probe_event(fd, ent); 2002146a1439SMasami Hiramatsu if (ret >= 0) 2003bbbb521bSMasami Hiramatsu strlist__remove(namelist, ent); 2004bbbb521bSMasami Hiramatsu } 2005bbbb521bSMasami Hiramatsu } 2006146a1439SMasami Hiramatsu if (found == 0 && ret >= 0) 2007146a1439SMasami Hiramatsu pr_info("Info: Event \"%s\" does not exist.\n", buf); 2008146a1439SMasami Hiramatsu 2009146a1439SMasami Hiramatsu return ret; 2010bbbb521bSMasami Hiramatsu } 2011fa28244dSMasami Hiramatsu 2012146a1439SMasami Hiramatsu int del_perf_probe_events(struct strlist *dellist) 2013fa28244dSMasami Hiramatsu { 2014146a1439SMasami Hiramatsu int fd, ret = 0; 2015fa28244dSMasami Hiramatsu const char *group, *event; 2016fa28244dSMasami Hiramatsu char *p, *str; 2017fa28244dSMasami Hiramatsu struct str_node *ent; 2018fa28244dSMasami Hiramatsu struct strlist *namelist; 2019fa28244dSMasami Hiramatsu 2020f4d7da49SMasami Hiramatsu fd = open_kprobe_events(true); 2021146a1439SMasami Hiramatsu if (fd < 0) 2022146a1439SMasami Hiramatsu return fd; 2023146a1439SMasami Hiramatsu 2024fa28244dSMasami Hiramatsu /* Get current event names */ 20250e60836bSSrikar Dronamraju namelist = get_probe_trace_event_names(fd, true); 2026146a1439SMasami Hiramatsu if (namelist == NULL) 2027146a1439SMasami Hiramatsu return -EINVAL; 2028fa28244dSMasami Hiramatsu 2029adf365f4SMasami Hiramatsu strlist__for_each(ent, dellist) { 203002b95dadSMasami Hiramatsu str = strdup(ent->s); 203102b95dadSMasami Hiramatsu if (str == NULL) { 203202b95dadSMasami Hiramatsu ret = -ENOMEM; 203302b95dadSMasami Hiramatsu break; 203402b95dadSMasami Hiramatsu } 2035bbbb521bSMasami Hiramatsu pr_debug("Parsing: %s\n", str); 2036fa28244dSMasami Hiramatsu p = strchr(str, ':'); 2037fa28244dSMasami Hiramatsu if (p) { 2038fa28244dSMasami Hiramatsu group = str; 2039fa28244dSMasami Hiramatsu *p = '\0'; 2040fa28244dSMasami Hiramatsu event = p + 1; 2041fa28244dSMasami Hiramatsu } else { 2042bbbb521bSMasami Hiramatsu group = "*"; 2043fa28244dSMasami Hiramatsu event = str; 2044fa28244dSMasami Hiramatsu } 2045bbbb521bSMasami Hiramatsu pr_debug("Group: %s, Event: %s\n", group, event); 20460e60836bSSrikar Dronamraju ret = del_trace_probe_event(fd, group, event, namelist); 2047fa28244dSMasami Hiramatsu free(str); 2048146a1439SMasami Hiramatsu if (ret < 0) 2049146a1439SMasami Hiramatsu break; 2050fa28244dSMasami Hiramatsu } 2051fa28244dSMasami Hiramatsu strlist__delete(namelist); 2052fa28244dSMasami Hiramatsu close(fd); 2053146a1439SMasami Hiramatsu 2054146a1439SMasami Hiramatsu return ret; 2055fa28244dSMasami Hiramatsu } 20563c42258cSMasami Hiramatsu /* TODO: don't use a global variable for filter ... */ 20573c42258cSMasami Hiramatsu static struct strfilter *available_func_filter; 2058fa28244dSMasami Hiramatsu 2059e80711caSMasami Hiramatsu /* 20603c42258cSMasami Hiramatsu * If a symbol corresponds to a function with global binding and 20613c42258cSMasami Hiramatsu * matches filter return 0. For all others return 1. 2062e80711caSMasami Hiramatsu */ 20633c42258cSMasami Hiramatsu static int filter_available_functions(struct map *map __unused, 2064e80711caSMasami Hiramatsu struct symbol *sym) 2065e80711caSMasami Hiramatsu { 20663c42258cSMasami Hiramatsu if (sym->binding == STB_GLOBAL && 20673c42258cSMasami Hiramatsu strfilter__compare(available_func_filter, sym->name)) 2068e80711caSMasami Hiramatsu return 0; 20693c42258cSMasami Hiramatsu return 1; 2070e80711caSMasami Hiramatsu } 2071e80711caSMasami Hiramatsu 20723c42258cSMasami Hiramatsu int show_available_funcs(const char *module, struct strfilter *_filter) 2073e80711caSMasami Hiramatsu { 2074e80711caSMasami Hiramatsu struct map *map; 2075e80711caSMasami Hiramatsu int ret; 2076e80711caSMasami Hiramatsu 2077e80711caSMasami Hiramatsu setup_pager(); 2078e80711caSMasami Hiramatsu 2079e80711caSMasami Hiramatsu ret = init_vmlinux(); 2080e80711caSMasami Hiramatsu if (ret < 0) 2081e80711caSMasami Hiramatsu return ret; 2082e80711caSMasami Hiramatsu 2083e80711caSMasami Hiramatsu map = kernel_get_module_map(module); 2084e80711caSMasami Hiramatsu if (!map) { 2085e80711caSMasami Hiramatsu pr_err("Failed to find %s map.\n", (module) ? : "kernel"); 2086e80711caSMasami Hiramatsu return -EINVAL; 2087e80711caSMasami Hiramatsu } 20883c42258cSMasami Hiramatsu available_func_filter = _filter; 20893c42258cSMasami Hiramatsu if (map__load(map, filter_available_functions)) { 2090e80711caSMasami Hiramatsu pr_err("Failed to load map.\n"); 2091e80711caSMasami Hiramatsu return -EINVAL; 2092e80711caSMasami Hiramatsu } 2093e80711caSMasami Hiramatsu if (!dso__sorted_by_name(map->dso, map->type)) 2094e80711caSMasami Hiramatsu dso__sort_by_name(map->dso, map->type); 2095e80711caSMasami Hiramatsu 2096e80711caSMasami Hiramatsu dso__fprintf_symbols_by_name(map->dso, map->type, stdout); 2097e80711caSMasami Hiramatsu return 0; 2098e80711caSMasami Hiramatsu } 2099