150656eecSMasami Hiramatsu /* 20e60836bSSrikar Dronamraju * probe-event.c : perf-probe definition to probe_events format converter 350656eecSMasami Hiramatsu * 450656eecSMasami Hiramatsu * Written by Masami Hiramatsu <mhiramat@redhat.com> 550656eecSMasami Hiramatsu * 650656eecSMasami Hiramatsu * This program is free software; you can redistribute it and/or modify 750656eecSMasami Hiramatsu * it under the terms of the GNU General Public License as published by 850656eecSMasami Hiramatsu * the Free Software Foundation; either version 2 of the License, or 950656eecSMasami Hiramatsu * (at your option) any later version. 1050656eecSMasami Hiramatsu * 1150656eecSMasami Hiramatsu * This program is distributed in the hope that it will be useful, 1250656eecSMasami Hiramatsu * but WITHOUT ANY WARRANTY; without even the implied warranty of 1350656eecSMasami Hiramatsu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1450656eecSMasami Hiramatsu * GNU General Public License for more details. 1550656eecSMasami Hiramatsu * 1650656eecSMasami Hiramatsu * You should have received a copy of the GNU General Public License 1750656eecSMasami Hiramatsu * along with this program; if not, write to the Free Software 1850656eecSMasami Hiramatsu * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 1950656eecSMasami Hiramatsu * 2050656eecSMasami Hiramatsu */ 2150656eecSMasami Hiramatsu 2250656eecSMasami Hiramatsu #include <sys/utsname.h> 2350656eecSMasami Hiramatsu #include <sys/types.h> 2450656eecSMasami Hiramatsu #include <sys/stat.h> 2550656eecSMasami Hiramatsu #include <fcntl.h> 2650656eecSMasami Hiramatsu #include <errno.h> 2750656eecSMasami Hiramatsu #include <stdio.h> 2850656eecSMasami Hiramatsu #include <unistd.h> 2950656eecSMasami Hiramatsu #include <stdlib.h> 3050656eecSMasami Hiramatsu #include <string.h> 314de189feSMasami Hiramatsu #include <stdarg.h> 324de189feSMasami Hiramatsu #include <limits.h> 33e80711caSMasami Hiramatsu #include <elf.h> 3450656eecSMasami Hiramatsu 3531facc5fSMasami Hiramatsu #include "util.h" 3650656eecSMasami Hiramatsu #include "event.h" 374de189feSMasami Hiramatsu #include "strlist.h" 3850656eecSMasami Hiramatsu #include "debug.h" 3972041334SMasami Hiramatsu #include "cache.h" 40631c9defSMasami Hiramatsu #include "color.h" 41e0faa8d3SMasami Hiramatsu #include "symbol.h" 42e0faa8d3SMasami Hiramatsu #include "thread.h" 437ca5989dSMasami Hiramatsu #include "debugfs.h" 444b4da7f7SMasami Hiramatsu #include "trace-event.h" /* For __unused */ 4550656eecSMasami Hiramatsu #include "probe-event.h" 464235b045SMasami Hiramatsu #include "probe-finder.h" 47225466f1SSrikar Dronamraju #include "session.h" 4850656eecSMasami Hiramatsu 4950656eecSMasami Hiramatsu #define MAX_CMDLEN 256 5050656eecSMasami Hiramatsu #define 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); 74225466f1SSrikar Dronamraju static int convert_name_to_addr(struct perf_probe_event *pev, 75225466f1SSrikar Dronamraju const char *exec); 76d28c6223SArnaldo Carvalho de Melo static struct machine machine; 77e0faa8d3SMasami Hiramatsu 78469b9b88SMasami Hiramatsu /* Initialize symbol maps and path of vmlinux/modules */ 79146a1439SMasami Hiramatsu static int init_vmlinux(void) 80e0faa8d3SMasami Hiramatsu { 81146a1439SMasami Hiramatsu int ret; 82146a1439SMasami Hiramatsu 83e0faa8d3SMasami Hiramatsu symbol_conf.sort_by_name = true; 84e0faa8d3SMasami Hiramatsu if (symbol_conf.vmlinux_name == NULL) 85e0faa8d3SMasami Hiramatsu symbol_conf.try_vmlinux_path = true; 86e0faa8d3SMasami Hiramatsu else 87e0faa8d3SMasami Hiramatsu pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name); 88146a1439SMasami Hiramatsu ret = symbol__init(); 89146a1439SMasami Hiramatsu if (ret < 0) { 90146a1439SMasami Hiramatsu pr_debug("Failed to init symbol map.\n"); 91146a1439SMasami Hiramatsu goto out; 92146a1439SMasami Hiramatsu } 93e0faa8d3SMasami Hiramatsu 94469b9b88SMasami Hiramatsu ret = machine__init(&machine, "", HOST_KERNEL_ID); 95d28c6223SArnaldo Carvalho de Melo if (ret < 0) 96d28c6223SArnaldo Carvalho de Melo goto out; 97d28c6223SArnaldo Carvalho de Melo 98469b9b88SMasami Hiramatsu if (machine__create_kernel_maps(&machine) < 0) { 990e43e5d2SMasami Hiramatsu pr_debug("machine__create_kernel_maps() failed.\n"); 100469b9b88SMasami Hiramatsu goto out; 101469b9b88SMasami Hiramatsu } 102146a1439SMasami Hiramatsu out: 103146a1439SMasami Hiramatsu if (ret < 0) 104146a1439SMasami Hiramatsu pr_warning("Failed to init vmlinux path.\n"); 105146a1439SMasami Hiramatsu return ret; 106e0faa8d3SMasami Hiramatsu } 107e0faa8d3SMasami Hiramatsu 108469b9b88SMasami Hiramatsu static struct symbol *__find_kernel_function_by_name(const char *name, 109469b9b88SMasami Hiramatsu struct map **mapp) 110e0faa8d3SMasami Hiramatsu { 111469b9b88SMasami Hiramatsu return machine__find_kernel_function_by_name(&machine, name, mapp, 112469b9b88SMasami Hiramatsu NULL); 113e0faa8d3SMasami Hiramatsu } 114469b9b88SMasami Hiramatsu 115e80711caSMasami Hiramatsu static struct map *kernel_get_module_map(const char *module) 116e80711caSMasami Hiramatsu { 117e80711caSMasami Hiramatsu struct rb_node *nd; 118e80711caSMasami Hiramatsu struct map_groups *grp = &machine.kmaps; 119e80711caSMasami Hiramatsu 12014a8fd7cSMasami Hiramatsu /* A file path -- this is an offline module */ 12114a8fd7cSMasami Hiramatsu if (module && strchr(module, '/')) 12214a8fd7cSMasami Hiramatsu return machine__new_module(&machine, 0, module); 12314a8fd7cSMasami Hiramatsu 124e80711caSMasami Hiramatsu if (!module) 125e80711caSMasami Hiramatsu module = "kernel"; 126e80711caSMasami Hiramatsu 127e80711caSMasami Hiramatsu for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { 128e80711caSMasami Hiramatsu struct map *pos = rb_entry(nd, struct map, rb_node); 129e80711caSMasami Hiramatsu if (strncmp(pos->dso->short_name + 1, module, 130e80711caSMasami Hiramatsu pos->dso->short_name_len - 2) == 0) { 131e80711caSMasami Hiramatsu return pos; 132e80711caSMasami Hiramatsu } 133e80711caSMasami Hiramatsu } 134e80711caSMasami Hiramatsu return NULL; 135e80711caSMasami Hiramatsu } 136e80711caSMasami Hiramatsu 137e80711caSMasami Hiramatsu static struct dso *kernel_get_module_dso(const char *module) 138469b9b88SMasami Hiramatsu { 139469b9b88SMasami Hiramatsu struct dso *dso; 140fd930ff9SFranck Bui-Huu struct map *map; 141fd930ff9SFranck Bui-Huu const char *vmlinux_name; 142469b9b88SMasami Hiramatsu 143469b9b88SMasami Hiramatsu if (module) { 144469b9b88SMasami Hiramatsu list_for_each_entry(dso, &machine.kernel_dsos, node) { 145469b9b88SMasami Hiramatsu if (strncmp(dso->short_name + 1, module, 146469b9b88SMasami Hiramatsu dso->short_name_len - 2) == 0) 147469b9b88SMasami Hiramatsu goto found; 148469b9b88SMasami Hiramatsu } 149469b9b88SMasami Hiramatsu pr_debug("Failed to find module %s.\n", module); 150469b9b88SMasami Hiramatsu return NULL; 151fd930ff9SFranck Bui-Huu } 152fd930ff9SFranck Bui-Huu 153fd930ff9SFranck Bui-Huu map = machine.vmlinux_maps[MAP__FUNCTION]; 154fd930ff9SFranck Bui-Huu dso = map->dso; 155fd930ff9SFranck Bui-Huu 156fd930ff9SFranck Bui-Huu vmlinux_name = symbol_conf.vmlinux_name; 157fd930ff9SFranck Bui-Huu if (vmlinux_name) { 158fd930ff9SFranck Bui-Huu if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0) 159fd930ff9SFranck Bui-Huu return NULL; 160469b9b88SMasami Hiramatsu } else { 161c3a34e06SFranck Bui-Huu if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { 162469b9b88SMasami Hiramatsu pr_debug("Failed to load kernel map.\n"); 163469b9b88SMasami Hiramatsu return NULL; 164469b9b88SMasami Hiramatsu } 165469b9b88SMasami Hiramatsu } 166469b9b88SMasami Hiramatsu found: 167e80711caSMasami Hiramatsu return dso; 168e80711caSMasami Hiramatsu } 169e80711caSMasami Hiramatsu 170e80711caSMasami Hiramatsu const char *kernel_get_module_path(const char *module) 171e80711caSMasami Hiramatsu { 172e80711caSMasami Hiramatsu struct dso *dso = kernel_get_module_dso(module); 173e80711caSMasami Hiramatsu return (dso) ? dso->long_name : NULL; 174469b9b88SMasami Hiramatsu } 175469b9b88SMasami Hiramatsu 176225466f1SSrikar Dronamraju static int init_user_exec(void) 177225466f1SSrikar Dronamraju { 178225466f1SSrikar Dronamraju int ret = 0; 179225466f1SSrikar Dronamraju 180225466f1SSrikar Dronamraju symbol_conf.try_vmlinux_path = false; 181225466f1SSrikar Dronamraju symbol_conf.sort_by_name = true; 182225466f1SSrikar Dronamraju ret = symbol__init(); 183225466f1SSrikar Dronamraju 184225466f1SSrikar Dronamraju if (ret < 0) 185225466f1SSrikar Dronamraju pr_debug("Failed to init symbol map.\n"); 186225466f1SSrikar Dronamraju 187225466f1SSrikar Dronamraju return ret; 188225466f1SSrikar Dronamraju } 189225466f1SSrikar Dronamraju 190225466f1SSrikar Dronamraju static int convert_to_perf_probe_point(struct probe_trace_point *tp, 191225466f1SSrikar Dronamraju struct perf_probe_point *pp) 192225466f1SSrikar Dronamraju { 193225466f1SSrikar Dronamraju pp->function = strdup(tp->symbol); 194225466f1SSrikar Dronamraju 195225466f1SSrikar Dronamraju if (pp->function == NULL) 196225466f1SSrikar Dronamraju return -ENOMEM; 197225466f1SSrikar Dronamraju 198225466f1SSrikar Dronamraju pp->offset = tp->offset; 199225466f1SSrikar Dronamraju pp->retprobe = tp->retprobe; 200225466f1SSrikar Dronamraju 201225466f1SSrikar Dronamraju return 0; 202225466f1SSrikar Dronamraju } 203225466f1SSrikar Dronamraju 204469b9b88SMasami Hiramatsu #ifdef DWARF_SUPPORT 205ff741783SMasami Hiramatsu /* Open new debuginfo of given module */ 206ff741783SMasami Hiramatsu static struct debuginfo *open_debuginfo(const char *module) 207469b9b88SMasami Hiramatsu { 20814a8fd7cSMasami Hiramatsu const char *path; 20914a8fd7cSMasami Hiramatsu 21014a8fd7cSMasami Hiramatsu /* A file path -- this is an offline module */ 21114a8fd7cSMasami Hiramatsu if (module && strchr(module, '/')) 21214a8fd7cSMasami Hiramatsu path = module; 21314a8fd7cSMasami Hiramatsu else { 21414a8fd7cSMasami Hiramatsu path = kernel_get_module_path(module); 215ff741783SMasami Hiramatsu 216469b9b88SMasami Hiramatsu if (!path) { 2170e43e5d2SMasami Hiramatsu pr_err("Failed to find path of %s module.\n", 2180e43e5d2SMasami Hiramatsu module ?: "kernel"); 219ff741783SMasami Hiramatsu return NULL; 220469b9b88SMasami Hiramatsu } 22114a8fd7cSMasami Hiramatsu } 222ff741783SMasami Hiramatsu return debuginfo__new(path); 223e0faa8d3SMasami Hiramatsu } 2244b4da7f7SMasami Hiramatsu 2250e60836bSSrikar Dronamraju /* 2260e60836bSSrikar Dronamraju * Convert trace point to probe point with debuginfo 2270e60836bSSrikar Dronamraju * Currently only handles kprobes. 2280e60836bSSrikar Dronamraju */ 2290e60836bSSrikar Dronamraju static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 2304b4da7f7SMasami Hiramatsu struct perf_probe_point *pp) 2314b4da7f7SMasami Hiramatsu { 2324b4da7f7SMasami Hiramatsu struct symbol *sym; 233469b9b88SMasami Hiramatsu struct map *map; 234469b9b88SMasami Hiramatsu u64 addr; 235469b9b88SMasami Hiramatsu int ret = -ENOENT; 236ff741783SMasami Hiramatsu struct debuginfo *dinfo; 2374b4da7f7SMasami Hiramatsu 238469b9b88SMasami Hiramatsu sym = __find_kernel_function_by_name(tp->symbol, &map); 2394b4da7f7SMasami Hiramatsu if (sym) { 240469b9b88SMasami Hiramatsu addr = map->unmap_ip(map, sym->start + tp->offset); 2419486aa38SArnaldo Carvalho de Melo pr_debug("try to find %s+%ld@%" PRIx64 "\n", tp->symbol, 242469b9b88SMasami Hiramatsu tp->offset, addr); 243ff741783SMasami Hiramatsu 244ff741783SMasami Hiramatsu dinfo = debuginfo__new_online_kernel(addr); 245ff741783SMasami Hiramatsu if (dinfo) { 246ff741783SMasami Hiramatsu ret = debuginfo__find_probe_point(dinfo, 247ff741783SMasami Hiramatsu (unsigned long)addr, pp); 248ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 249ff741783SMasami Hiramatsu } else { 250ff741783SMasami Hiramatsu pr_debug("Failed to open debuginfo at 0x%" PRIx64 "\n", 251ff741783SMasami Hiramatsu addr); 252ff741783SMasami Hiramatsu ret = -ENOENT; 253ff741783SMasami Hiramatsu } 254146a1439SMasami Hiramatsu } 2554b4da7f7SMasami Hiramatsu if (ret <= 0) { 256146a1439SMasami Hiramatsu pr_debug("Failed to find corresponding probes from " 257146a1439SMasami Hiramatsu "debuginfo. Use kprobe event information.\n"); 258225466f1SSrikar Dronamraju return convert_to_perf_probe_point(tp, pp); 2594b4da7f7SMasami Hiramatsu } 2604b4da7f7SMasami Hiramatsu pp->retprobe = tp->retprobe; 261146a1439SMasami Hiramatsu 262146a1439SMasami Hiramatsu return 0; 2634b4da7f7SMasami Hiramatsu } 2644b4da7f7SMasami Hiramatsu 265190b57fcSMasami Hiramatsu static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, 266190b57fcSMasami Hiramatsu int ntevs, const char *module) 267190b57fcSMasami Hiramatsu { 26814a8fd7cSMasami Hiramatsu int i, ret = 0; 26914a8fd7cSMasami Hiramatsu char *tmp; 27014a8fd7cSMasami Hiramatsu 27114a8fd7cSMasami Hiramatsu if (!module) 27214a8fd7cSMasami Hiramatsu return 0; 27314a8fd7cSMasami Hiramatsu 27414a8fd7cSMasami Hiramatsu tmp = strrchr(module, '/'); 27514a8fd7cSMasami Hiramatsu if (tmp) { 27614a8fd7cSMasami Hiramatsu /* This is a module path -- get the module name */ 27714a8fd7cSMasami Hiramatsu module = strdup(tmp + 1); 27814a8fd7cSMasami Hiramatsu if (!module) 27914a8fd7cSMasami Hiramatsu return -ENOMEM; 28014a8fd7cSMasami Hiramatsu tmp = strchr(module, '.'); 28114a8fd7cSMasami Hiramatsu if (tmp) 28214a8fd7cSMasami Hiramatsu *tmp = '\0'; 28314a8fd7cSMasami Hiramatsu tmp = (char *)module; /* For free() */ 28414a8fd7cSMasami Hiramatsu } 28514a8fd7cSMasami Hiramatsu 286190b57fcSMasami Hiramatsu for (i = 0; i < ntevs; i++) { 287190b57fcSMasami Hiramatsu tevs[i].point.module = strdup(module); 28814a8fd7cSMasami Hiramatsu if (!tevs[i].point.module) { 28914a8fd7cSMasami Hiramatsu ret = -ENOMEM; 29014a8fd7cSMasami Hiramatsu break; 291190b57fcSMasami Hiramatsu } 29214a8fd7cSMasami Hiramatsu } 29314a8fd7cSMasami Hiramatsu 29414a8fd7cSMasami Hiramatsu if (tmp) 29514a8fd7cSMasami Hiramatsu free(tmp); 29614a8fd7cSMasami Hiramatsu 29714a8fd7cSMasami Hiramatsu return ret; 298190b57fcSMasami Hiramatsu } 299190b57fcSMasami Hiramatsu 3004b4da7f7SMasami Hiramatsu /* Try to find perf_probe_event with debuginfo */ 3010e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 3020e60836bSSrikar Dronamraju struct probe_trace_event **tevs, 3034eced234SSrikar Dronamraju int max_tevs, const char *target) 3044b4da7f7SMasami Hiramatsu { 3054b4da7f7SMasami Hiramatsu bool need_dwarf = perf_probe_event_need_dwarf(pev); 306225466f1SSrikar Dronamraju struct debuginfo *dinfo; 307190b57fcSMasami Hiramatsu int ntevs, ret = 0; 3084b4da7f7SMasami Hiramatsu 309225466f1SSrikar Dronamraju if (pev->uprobes) { 310225466f1SSrikar Dronamraju if (need_dwarf) { 311225466f1SSrikar Dronamraju pr_warning("Debuginfo-analysis is not yet supported" 312225466f1SSrikar Dronamraju " with -x/--exec option.\n"); 313225466f1SSrikar Dronamraju return -ENOSYS; 314225466f1SSrikar Dronamraju } 315225466f1SSrikar Dronamraju return convert_name_to_addr(pev, target); 316225466f1SSrikar Dronamraju } 317225466f1SSrikar Dronamraju 318225466f1SSrikar Dronamraju dinfo = open_debuginfo(target); 319225466f1SSrikar Dronamraju 320ff741783SMasami Hiramatsu if (!dinfo) { 321146a1439SMasami Hiramatsu if (need_dwarf) { 322146a1439SMasami Hiramatsu pr_warning("Failed to open debuginfo file.\n"); 323ff741783SMasami Hiramatsu return -ENOENT; 324146a1439SMasami Hiramatsu } 325ff741783SMasami Hiramatsu pr_debug("Could not open debuginfo. Try to use symbols.\n"); 3264b4da7f7SMasami Hiramatsu return 0; 3274b4da7f7SMasami Hiramatsu } 3284b4da7f7SMasami Hiramatsu 329ff741783SMasami Hiramatsu /* Searching trace events corresponding to a probe event */ 330ff741783SMasami Hiramatsu ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs); 331ff741783SMasami Hiramatsu 332ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 3334b4da7f7SMasami Hiramatsu 334146a1439SMasami Hiramatsu if (ntevs > 0) { /* Succeeded to find trace events */ 3350e60836bSSrikar Dronamraju pr_debug("find %d probe_trace_events.\n", ntevs); 3364eced234SSrikar Dronamraju if (target) 337190b57fcSMasami Hiramatsu ret = add_module_to_probe_trace_events(*tevs, ntevs, 3384eced234SSrikar Dronamraju target); 339190b57fcSMasami Hiramatsu return ret < 0 ? ret : ntevs; 340146a1439SMasami Hiramatsu } 3414b4da7f7SMasami Hiramatsu 342146a1439SMasami Hiramatsu if (ntevs == 0) { /* No error but failed to find probe point. */ 343146a1439SMasami Hiramatsu pr_warning("Probe point '%s' not found.\n", 3444b4da7f7SMasami Hiramatsu synthesize_perf_probe_point(&pev->point)); 345146a1439SMasami Hiramatsu return -ENOENT; 346146a1439SMasami Hiramatsu } 347146a1439SMasami Hiramatsu /* Error path : ntevs < 0 */ 34815eca306SMasami Hiramatsu pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); 34915eca306SMasami Hiramatsu if (ntevs == -EBADF) { 35015eca306SMasami Hiramatsu pr_warning("Warning: No dwarf info found in the vmlinux - " 35115eca306SMasami Hiramatsu "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); 35215eca306SMasami Hiramatsu if (!need_dwarf) { 3530e43e5d2SMasami Hiramatsu pr_debug("Trying to use symbols.\n"); 3544b4da7f7SMasami Hiramatsu return 0; 3554b4da7f7SMasami Hiramatsu } 35615eca306SMasami Hiramatsu } 35715eca306SMasami Hiramatsu return ntevs; 35815eca306SMasami Hiramatsu } 3594b4da7f7SMasami Hiramatsu 3607cf0b79eSMasami Hiramatsu /* 3617cf0b79eSMasami Hiramatsu * Find a src file from a DWARF tag path. Prepend optional source path prefix 3627cf0b79eSMasami Hiramatsu * and chop off leading directories that do not exist. Result is passed back as 3637cf0b79eSMasami Hiramatsu * a newly allocated path on success. 3647cf0b79eSMasami Hiramatsu * Return 0 if file was found and readable, -errno otherwise. 3657cf0b79eSMasami Hiramatsu */ 3666a330a3cSMasami Hiramatsu static int get_real_path(const char *raw_path, const char *comp_dir, 3676a330a3cSMasami Hiramatsu char **new_path) 3687cf0b79eSMasami Hiramatsu { 3696a330a3cSMasami Hiramatsu const char *prefix = symbol_conf.source_prefix; 3706a330a3cSMasami Hiramatsu 3716a330a3cSMasami Hiramatsu if (!prefix) { 3726a330a3cSMasami Hiramatsu if (raw_path[0] != '/' && comp_dir) 3736a330a3cSMasami Hiramatsu /* If not an absolute path, try to use comp_dir */ 3746a330a3cSMasami Hiramatsu prefix = comp_dir; 3756a330a3cSMasami Hiramatsu else { 3767cf0b79eSMasami Hiramatsu if (access(raw_path, R_OK) == 0) { 3777cf0b79eSMasami Hiramatsu *new_path = strdup(raw_path); 3787cf0b79eSMasami Hiramatsu return 0; 3797cf0b79eSMasami Hiramatsu } else 3807cf0b79eSMasami Hiramatsu return -errno; 3817cf0b79eSMasami Hiramatsu } 3826a330a3cSMasami Hiramatsu } 3837cf0b79eSMasami Hiramatsu 3846a330a3cSMasami Hiramatsu *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); 3857cf0b79eSMasami Hiramatsu if (!*new_path) 3867cf0b79eSMasami Hiramatsu return -ENOMEM; 3877cf0b79eSMasami Hiramatsu 3887cf0b79eSMasami Hiramatsu for (;;) { 3896a330a3cSMasami Hiramatsu sprintf(*new_path, "%s/%s", prefix, raw_path); 3907cf0b79eSMasami Hiramatsu 3917cf0b79eSMasami Hiramatsu if (access(*new_path, R_OK) == 0) 3927cf0b79eSMasami Hiramatsu return 0; 3937cf0b79eSMasami Hiramatsu 3946a330a3cSMasami Hiramatsu if (!symbol_conf.source_prefix) 3956a330a3cSMasami Hiramatsu /* In case of searching comp_dir, don't retry */ 3966a330a3cSMasami Hiramatsu return -errno; 3976a330a3cSMasami Hiramatsu 3987cf0b79eSMasami Hiramatsu switch (errno) { 3997cf0b79eSMasami Hiramatsu case ENAMETOOLONG: 4007cf0b79eSMasami Hiramatsu case ENOENT: 4017cf0b79eSMasami Hiramatsu case EROFS: 4027cf0b79eSMasami Hiramatsu case EFAULT: 4037cf0b79eSMasami Hiramatsu raw_path = strchr(++raw_path, '/'); 4047cf0b79eSMasami Hiramatsu if (!raw_path) { 4057cf0b79eSMasami Hiramatsu free(*new_path); 4067cf0b79eSMasami Hiramatsu *new_path = NULL; 4077cf0b79eSMasami Hiramatsu return -ENOENT; 4087cf0b79eSMasami Hiramatsu } 4097cf0b79eSMasami Hiramatsu continue; 4107cf0b79eSMasami Hiramatsu 4117cf0b79eSMasami Hiramatsu default: 4127cf0b79eSMasami Hiramatsu free(*new_path); 4137cf0b79eSMasami Hiramatsu *new_path = NULL; 4147cf0b79eSMasami Hiramatsu return -errno; 4157cf0b79eSMasami Hiramatsu } 4167cf0b79eSMasami Hiramatsu } 4177cf0b79eSMasami Hiramatsu } 4187cf0b79eSMasami Hiramatsu 4194b4da7f7SMasami Hiramatsu #define LINEBUF_SIZE 256 4204b4da7f7SMasami Hiramatsu #define NR_ADDITIONAL_LINES 2 4214b4da7f7SMasami Hiramatsu 422fde52dbdSFranck Bui-Huu static int __show_one_line(FILE *fp, int l, bool skip, bool show_num) 4234b4da7f7SMasami Hiramatsu { 4244b4da7f7SMasami Hiramatsu char buf[LINEBUF_SIZE]; 425befe3414SFranck Bui-Huu const char *color = show_num ? "" : PERF_COLOR_BLUE; 426befe3414SFranck Bui-Huu const char *prefix = NULL; 4274b4da7f7SMasami Hiramatsu 428befe3414SFranck Bui-Huu do { 4294b4da7f7SMasami Hiramatsu if (fgets(buf, LINEBUF_SIZE, fp) == NULL) 4304b4da7f7SMasami Hiramatsu goto error; 431befe3414SFranck Bui-Huu if (skip) 432befe3414SFranck Bui-Huu continue; 433befe3414SFranck Bui-Huu if (!prefix) { 434befe3414SFranck Bui-Huu prefix = show_num ? "%7d " : " "; 435befe3414SFranck Bui-Huu color_fprintf(stdout, color, prefix, l); 4364b4da7f7SMasami Hiramatsu } 437befe3414SFranck Bui-Huu color_fprintf(stdout, color, "%s", buf); 4384b4da7f7SMasami Hiramatsu 439befe3414SFranck Bui-Huu } while (strchr(buf, '\n') == NULL); 440146a1439SMasami Hiramatsu 441fde52dbdSFranck Bui-Huu return 1; 4424b4da7f7SMasami Hiramatsu error: 443fde52dbdSFranck Bui-Huu if (ferror(fp)) { 44432b2b6ecSFranck Bui-Huu pr_warning("File read error: %s\n", strerror(errno)); 445146a1439SMasami Hiramatsu return -1; 4464b4da7f7SMasami Hiramatsu } 447fde52dbdSFranck Bui-Huu return 0; 448fde52dbdSFranck Bui-Huu } 449fde52dbdSFranck Bui-Huu 450fde52dbdSFranck Bui-Huu static int _show_one_line(FILE *fp, int l, bool skip, bool show_num) 451fde52dbdSFranck Bui-Huu { 452fde52dbdSFranck Bui-Huu int rv = __show_one_line(fp, l, skip, show_num); 453fde52dbdSFranck Bui-Huu if (rv == 0) { 454fde52dbdSFranck Bui-Huu pr_warning("Source file is shorter than expected.\n"); 455fde52dbdSFranck Bui-Huu rv = -1; 456fde52dbdSFranck Bui-Huu } 457fde52dbdSFranck Bui-Huu return rv; 458fde52dbdSFranck Bui-Huu } 459fde52dbdSFranck Bui-Huu 460fde52dbdSFranck Bui-Huu #define show_one_line_with_num(f,l) _show_one_line(f,l,false,true) 461fde52dbdSFranck Bui-Huu #define show_one_line(f,l) _show_one_line(f,l,false,false) 462fde52dbdSFranck Bui-Huu #define skip_one_line(f,l) _show_one_line(f,l,true,false) 463fde52dbdSFranck Bui-Huu #define show_one_line_or_eof(f,l) __show_one_line(f,l,false,false) 4644b4da7f7SMasami Hiramatsu 4654b4da7f7SMasami Hiramatsu /* 4664b4da7f7SMasami Hiramatsu * Show line-range always requires debuginfo to find source file and 4674b4da7f7SMasami Hiramatsu * line number. 4684b4da7f7SMasami Hiramatsu */ 469469b9b88SMasami Hiramatsu int show_line_range(struct line_range *lr, const char *module) 4704b4da7f7SMasami Hiramatsu { 471d3b63d7aSMasami Hiramatsu int l = 1; 4724b4da7f7SMasami Hiramatsu struct line_node *ln; 473ff741783SMasami Hiramatsu struct debuginfo *dinfo; 4744b4da7f7SMasami Hiramatsu FILE *fp; 475ff741783SMasami Hiramatsu int ret; 4767cf0b79eSMasami Hiramatsu char *tmp; 4774b4da7f7SMasami Hiramatsu 4784b4da7f7SMasami Hiramatsu /* Search a line range */ 479146a1439SMasami Hiramatsu ret = init_vmlinux(); 480146a1439SMasami Hiramatsu if (ret < 0) 481146a1439SMasami Hiramatsu return ret; 482146a1439SMasami Hiramatsu 483ff741783SMasami Hiramatsu dinfo = open_debuginfo(module); 484ff741783SMasami Hiramatsu if (!dinfo) { 485146a1439SMasami Hiramatsu pr_warning("Failed to open debuginfo file.\n"); 486ff741783SMasami Hiramatsu return -ENOENT; 487146a1439SMasami Hiramatsu } 488146a1439SMasami Hiramatsu 489ff741783SMasami Hiramatsu ret = debuginfo__find_line_range(dinfo, lr); 490ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 491146a1439SMasami Hiramatsu if (ret == 0) { 492146a1439SMasami Hiramatsu pr_warning("Specified source line is not found.\n"); 493146a1439SMasami Hiramatsu return -ENOENT; 494146a1439SMasami Hiramatsu } else if (ret < 0) { 495146a1439SMasami Hiramatsu pr_warning("Debuginfo analysis failed. (%d)\n", ret); 496146a1439SMasami Hiramatsu return ret; 497146a1439SMasami Hiramatsu } 4984b4da7f7SMasami Hiramatsu 4997cf0b79eSMasami Hiramatsu /* Convert source file path */ 5007cf0b79eSMasami Hiramatsu tmp = lr->path; 5016a330a3cSMasami Hiramatsu ret = get_real_path(tmp, lr->comp_dir, &lr->path); 5027cf0b79eSMasami Hiramatsu free(tmp); /* Free old path */ 5037cf0b79eSMasami Hiramatsu if (ret < 0) { 5047cf0b79eSMasami Hiramatsu pr_warning("Failed to find source file. (%d)\n", ret); 5057cf0b79eSMasami Hiramatsu return ret; 5067cf0b79eSMasami Hiramatsu } 5077cf0b79eSMasami Hiramatsu 5084b4da7f7SMasami Hiramatsu setup_pager(); 5094b4da7f7SMasami Hiramatsu 5104b4da7f7SMasami Hiramatsu if (lr->function) 5118737ebdeSMasami Hiramatsu fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path, 5124b4da7f7SMasami Hiramatsu lr->start - lr->offset); 5134b4da7f7SMasami Hiramatsu else 51462c15fc4SFranck Bui-Huu fprintf(stdout, "<%s:%d>\n", lr->path, lr->start); 5154b4da7f7SMasami Hiramatsu 5164b4da7f7SMasami Hiramatsu fp = fopen(lr->path, "r"); 517146a1439SMasami Hiramatsu if (fp == NULL) { 518146a1439SMasami Hiramatsu pr_warning("Failed to open %s: %s\n", lr->path, 519146a1439SMasami Hiramatsu strerror(errno)); 520146a1439SMasami Hiramatsu return -errno; 521146a1439SMasami Hiramatsu } 5224b4da7f7SMasami Hiramatsu /* Skip to starting line number */ 52344b81e92SFranck Bui-Huu while (l < lr->start) { 524fde52dbdSFranck Bui-Huu ret = skip_one_line(fp, l++); 525146a1439SMasami Hiramatsu if (ret < 0) 526146a1439SMasami Hiramatsu goto end; 52744b81e92SFranck Bui-Huu } 5284b4da7f7SMasami Hiramatsu 5294b4da7f7SMasami Hiramatsu list_for_each_entry(ln, &lr->line_list, list) { 53044b81e92SFranck Bui-Huu for (; ln->line > l; l++) { 531fde52dbdSFranck Bui-Huu ret = show_one_line(fp, l - lr->offset); 53244b81e92SFranck Bui-Huu if (ret < 0) 53344b81e92SFranck Bui-Huu goto end; 53444b81e92SFranck Bui-Huu } 535fde52dbdSFranck Bui-Huu ret = show_one_line_with_num(fp, l++ - lr->offset); 536146a1439SMasami Hiramatsu if (ret < 0) 537146a1439SMasami Hiramatsu goto end; 5384b4da7f7SMasami Hiramatsu } 5394b4da7f7SMasami Hiramatsu 5404b4da7f7SMasami Hiramatsu if (lr->end == INT_MAX) 5414b4da7f7SMasami Hiramatsu lr->end = l + NR_ADDITIONAL_LINES; 542fde52dbdSFranck Bui-Huu while (l <= lr->end) { 543fde52dbdSFranck Bui-Huu ret = show_one_line_or_eof(fp, l++ - lr->offset); 544fde52dbdSFranck Bui-Huu if (ret <= 0) 54544b81e92SFranck Bui-Huu break; 54644b81e92SFranck Bui-Huu } 547146a1439SMasami Hiramatsu end: 5484b4da7f7SMasami Hiramatsu fclose(fp); 549146a1439SMasami Hiramatsu return ret; 5504b4da7f7SMasami Hiramatsu } 5514b4da7f7SMasami Hiramatsu 552ff741783SMasami Hiramatsu static int show_available_vars_at(struct debuginfo *dinfo, 553ff741783SMasami Hiramatsu struct perf_probe_event *pev, 554bd09d7b5SMasami Hiramatsu int max_vls, struct strfilter *_filter, 555bd09d7b5SMasami Hiramatsu bool externs) 556cf6eb489SMasami Hiramatsu { 557cf6eb489SMasami Hiramatsu char *buf; 558bd09d7b5SMasami Hiramatsu int ret, i, nvars; 559cf6eb489SMasami Hiramatsu struct str_node *node; 560cf6eb489SMasami Hiramatsu struct variable_list *vls = NULL, *vl; 561bd09d7b5SMasami Hiramatsu const char *var; 562cf6eb489SMasami Hiramatsu 563cf6eb489SMasami Hiramatsu buf = synthesize_perf_probe_point(&pev->point); 564cf6eb489SMasami Hiramatsu if (!buf) 565cf6eb489SMasami Hiramatsu return -EINVAL; 566cf6eb489SMasami Hiramatsu pr_debug("Searching variables at %s\n", buf); 567cf6eb489SMasami Hiramatsu 568ff741783SMasami Hiramatsu ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, 569ff741783SMasami Hiramatsu max_vls, externs); 570bd09d7b5SMasami Hiramatsu if (ret <= 0) { 571bd09d7b5SMasami Hiramatsu pr_err("Failed to find variables at %s (%d)\n", buf, ret); 572bd09d7b5SMasami Hiramatsu goto end; 573bd09d7b5SMasami Hiramatsu } 574bd09d7b5SMasami Hiramatsu /* Some variables are found */ 575cf6eb489SMasami Hiramatsu fprintf(stdout, "Available variables at %s\n", buf); 576cf6eb489SMasami Hiramatsu for (i = 0; i < ret; i++) { 577cf6eb489SMasami Hiramatsu vl = &vls[i]; 578cf6eb489SMasami Hiramatsu /* 579cf6eb489SMasami Hiramatsu * A probe point might be converted to 580cf6eb489SMasami Hiramatsu * several trace points. 581cf6eb489SMasami Hiramatsu */ 582cf6eb489SMasami Hiramatsu fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, 583cf6eb489SMasami Hiramatsu vl->point.offset); 584cf6eb489SMasami Hiramatsu free(vl->point.symbol); 585bd09d7b5SMasami Hiramatsu nvars = 0; 586cf6eb489SMasami Hiramatsu if (vl->vars) { 587bd09d7b5SMasami Hiramatsu strlist__for_each(node, vl->vars) { 588bd09d7b5SMasami Hiramatsu var = strchr(node->s, '\t') + 1; 589bd09d7b5SMasami Hiramatsu if (strfilter__compare(_filter, var)) { 590cf6eb489SMasami Hiramatsu fprintf(stdout, "\t\t%s\n", node->s); 591bd09d7b5SMasami Hiramatsu nvars++; 592bd09d7b5SMasami Hiramatsu } 593bd09d7b5SMasami Hiramatsu } 594cf6eb489SMasami Hiramatsu strlist__delete(vl->vars); 595bd09d7b5SMasami Hiramatsu } 596bd09d7b5SMasami Hiramatsu if (nvars == 0) 597bd09d7b5SMasami Hiramatsu fprintf(stdout, "\t\t(No matched variables)\n"); 598cf6eb489SMasami Hiramatsu } 599cf6eb489SMasami Hiramatsu free(vls); 600bd09d7b5SMasami Hiramatsu end: 601cf6eb489SMasami Hiramatsu free(buf); 602cf6eb489SMasami Hiramatsu return ret; 603cf6eb489SMasami Hiramatsu } 604cf6eb489SMasami Hiramatsu 605cf6eb489SMasami Hiramatsu /* Show available variables on given probe point */ 606cf6eb489SMasami Hiramatsu int show_available_vars(struct perf_probe_event *pevs, int npevs, 607bd09d7b5SMasami Hiramatsu int max_vls, const char *module, 608bd09d7b5SMasami Hiramatsu struct strfilter *_filter, bool externs) 609cf6eb489SMasami Hiramatsu { 610ff741783SMasami Hiramatsu int i, ret = 0; 611ff741783SMasami Hiramatsu struct debuginfo *dinfo; 612cf6eb489SMasami Hiramatsu 613cf6eb489SMasami Hiramatsu ret = init_vmlinux(); 614cf6eb489SMasami Hiramatsu if (ret < 0) 615cf6eb489SMasami Hiramatsu return ret; 616cf6eb489SMasami Hiramatsu 617ff741783SMasami Hiramatsu dinfo = open_debuginfo(module); 618ff741783SMasami Hiramatsu if (!dinfo) { 619ff741783SMasami Hiramatsu pr_warning("Failed to open debuginfo file.\n"); 620ff741783SMasami Hiramatsu return -ENOENT; 621ff741783SMasami Hiramatsu } 622ff741783SMasami Hiramatsu 623cc446446SMasami Hiramatsu setup_pager(); 624cc446446SMasami Hiramatsu 625ff741783SMasami Hiramatsu for (i = 0; i < npevs && ret >= 0; i++) 626ff741783SMasami Hiramatsu ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter, 627bd09d7b5SMasami Hiramatsu externs); 628ff741783SMasami Hiramatsu 629ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 630cf6eb489SMasami Hiramatsu return ret; 631cf6eb489SMasami Hiramatsu } 632cf6eb489SMasami Hiramatsu 6334b4da7f7SMasami Hiramatsu #else /* !DWARF_SUPPORT */ 6344b4da7f7SMasami Hiramatsu 6350e60836bSSrikar Dronamraju static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 6364b4da7f7SMasami Hiramatsu struct perf_probe_point *pp) 6374b4da7f7SMasami Hiramatsu { 638469b9b88SMasami Hiramatsu struct symbol *sym; 639469b9b88SMasami Hiramatsu 640469b9b88SMasami Hiramatsu sym = __find_kernel_function_by_name(tp->symbol, NULL); 641469b9b88SMasami Hiramatsu if (!sym) { 642469b9b88SMasami Hiramatsu pr_err("Failed to find symbol %s in kernel.\n", tp->symbol); 643469b9b88SMasami Hiramatsu return -ENOENT; 644469b9b88SMasami Hiramatsu } 645146a1439SMasami Hiramatsu 646225466f1SSrikar Dronamraju return convert_to_perf_probe_point(tp, pp); 6474b4da7f7SMasami Hiramatsu } 6484b4da7f7SMasami Hiramatsu 6490e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 6500e60836bSSrikar Dronamraju struct probe_trace_event **tevs __unused, 651225466f1SSrikar Dronamraju int max_tevs __unused, const char *target) 6524b4da7f7SMasami Hiramatsu { 653146a1439SMasami Hiramatsu if (perf_probe_event_need_dwarf(pev)) { 654146a1439SMasami Hiramatsu pr_warning("Debuginfo-analysis is not supported.\n"); 655146a1439SMasami Hiramatsu return -ENOSYS; 656146a1439SMasami Hiramatsu } 657225466f1SSrikar Dronamraju 658225466f1SSrikar Dronamraju if (pev->uprobes) 659225466f1SSrikar Dronamraju return convert_name_to_addr(pev, target); 660225466f1SSrikar Dronamraju 6614b4da7f7SMasami Hiramatsu return 0; 6624b4da7f7SMasami Hiramatsu } 6634b4da7f7SMasami Hiramatsu 664469b9b88SMasami Hiramatsu int show_line_range(struct line_range *lr __unused, const char *module __unused) 6654b4da7f7SMasami Hiramatsu { 666146a1439SMasami Hiramatsu pr_warning("Debuginfo-analysis is not supported.\n"); 667146a1439SMasami Hiramatsu return -ENOSYS; 6684b4da7f7SMasami Hiramatsu } 6694b4da7f7SMasami Hiramatsu 670cf6eb489SMasami Hiramatsu int show_available_vars(struct perf_probe_event *pevs __unused, 671469b9b88SMasami Hiramatsu int npevs __unused, int max_vls __unused, 672bd09d7b5SMasami Hiramatsu const char *module __unused, 673bd09d7b5SMasami Hiramatsu struct strfilter *filter __unused, 674bd09d7b5SMasami Hiramatsu bool externs __unused) 675cf6eb489SMasami Hiramatsu { 676cf6eb489SMasami Hiramatsu pr_warning("Debuginfo-analysis is not supported.\n"); 677cf6eb489SMasami Hiramatsu return -ENOSYS; 678cf6eb489SMasami Hiramatsu } 679e0faa8d3SMasami Hiramatsu #endif 680e0faa8d3SMasami Hiramatsu 68121dd9ae5SFranck Bui-Huu static int parse_line_num(char **ptr, int *val, const char *what) 68221dd9ae5SFranck Bui-Huu { 68321dd9ae5SFranck Bui-Huu const char *start = *ptr; 68421dd9ae5SFranck Bui-Huu 68521dd9ae5SFranck Bui-Huu errno = 0; 68621dd9ae5SFranck Bui-Huu *val = strtol(*ptr, ptr, 0); 68721dd9ae5SFranck Bui-Huu if (errno || *ptr == start) { 68821dd9ae5SFranck Bui-Huu semantic_error("'%s' is not a valid number.\n", what); 68921dd9ae5SFranck Bui-Huu return -EINVAL; 69021dd9ae5SFranck Bui-Huu } 69121dd9ae5SFranck Bui-Huu return 0; 69221dd9ae5SFranck Bui-Huu } 69321dd9ae5SFranck Bui-Huu 6949d95b580SFranck Bui-Huu /* 6959d95b580SFranck Bui-Huu * Stuff 'lr' according to the line range described by 'arg'. 6969d95b580SFranck Bui-Huu * The line range syntax is described by: 6979d95b580SFranck Bui-Huu * 6989d95b580SFranck Bui-Huu * SRC[:SLN[+NUM|-ELN]] 699e116dfa1SMasami Hiramatsu * FNC[@SRC][:SLN[+NUM|-ELN]] 7009d95b580SFranck Bui-Huu */ 701146a1439SMasami Hiramatsu int parse_line_range_desc(const char *arg, struct line_range *lr) 702631c9defSMasami Hiramatsu { 703e116dfa1SMasami Hiramatsu char *range, *file, *name = strdup(arg); 70421dd9ae5SFranck Bui-Huu int err; 7059d95b580SFranck Bui-Huu 70621dd9ae5SFranck Bui-Huu if (!name) 70721dd9ae5SFranck Bui-Huu return -ENOMEM; 70821dd9ae5SFranck Bui-Huu 70921dd9ae5SFranck Bui-Huu lr->start = 0; 71021dd9ae5SFranck Bui-Huu lr->end = INT_MAX; 71121dd9ae5SFranck Bui-Huu 71221dd9ae5SFranck Bui-Huu range = strchr(name, ':'); 71321dd9ae5SFranck Bui-Huu if (range) { 71421dd9ae5SFranck Bui-Huu *range++ = '\0'; 71521dd9ae5SFranck Bui-Huu 71621dd9ae5SFranck Bui-Huu err = parse_line_num(&range, &lr->start, "start line"); 71721dd9ae5SFranck Bui-Huu if (err) 71821dd9ae5SFranck Bui-Huu goto err; 71921dd9ae5SFranck Bui-Huu 72021dd9ae5SFranck Bui-Huu if (*range == '+' || *range == '-') { 72121dd9ae5SFranck Bui-Huu const char c = *range++; 72221dd9ae5SFranck Bui-Huu 72321dd9ae5SFranck Bui-Huu err = parse_line_num(&range, &lr->end, "end line"); 72421dd9ae5SFranck Bui-Huu if (err) 72521dd9ae5SFranck Bui-Huu goto err; 72621dd9ae5SFranck Bui-Huu 72721dd9ae5SFranck Bui-Huu if (c == '+') { 72821dd9ae5SFranck Bui-Huu lr->end += lr->start; 72921dd9ae5SFranck Bui-Huu /* 730dda4ab34SMasami Hiramatsu * Adjust the number of lines here. 731dda4ab34SMasami Hiramatsu * If the number of lines == 1, the 732dda4ab34SMasami Hiramatsu * the end of line should be equal to 733dda4ab34SMasami Hiramatsu * the start of line. 734dda4ab34SMasami Hiramatsu */ 73521dd9ae5SFranck Bui-Huu lr->end--; 73621dd9ae5SFranck Bui-Huu } 73721dd9ae5SFranck Bui-Huu } 73821dd9ae5SFranck Bui-Huu 739d3b63d7aSMasami Hiramatsu pr_debug("Line range is %d to %d\n", lr->start, lr->end); 74021dd9ae5SFranck Bui-Huu 74121dd9ae5SFranck Bui-Huu err = -EINVAL; 742d3b63d7aSMasami Hiramatsu if (lr->start > lr->end) { 743631c9defSMasami Hiramatsu semantic_error("Start line must be smaller" 744146a1439SMasami Hiramatsu " than end line.\n"); 74521dd9ae5SFranck Bui-Huu goto err; 746146a1439SMasami Hiramatsu } 74721dd9ae5SFranck Bui-Huu if (*range != '\0') { 74821dd9ae5SFranck Bui-Huu semantic_error("Tailing with invalid str '%s'.\n", range); 74921dd9ae5SFranck Bui-Huu goto err; 750146a1439SMasami Hiramatsu } 751d3b63d7aSMasami Hiramatsu } 75202b95dadSMasami Hiramatsu 753e116dfa1SMasami Hiramatsu file = strchr(name, '@'); 754e116dfa1SMasami Hiramatsu if (file) { 755e116dfa1SMasami Hiramatsu *file = '\0'; 756e116dfa1SMasami Hiramatsu lr->file = strdup(++file); 757e116dfa1SMasami Hiramatsu if (lr->file == NULL) { 758e116dfa1SMasami Hiramatsu err = -ENOMEM; 759e116dfa1SMasami Hiramatsu goto err; 760e116dfa1SMasami Hiramatsu } 761e116dfa1SMasami Hiramatsu lr->function = name; 762e116dfa1SMasami Hiramatsu } else if (strchr(name, '.')) 76321dd9ae5SFranck Bui-Huu lr->file = name; 764631c9defSMasami Hiramatsu else 76521dd9ae5SFranck Bui-Huu lr->function = name; 766146a1439SMasami Hiramatsu 767146a1439SMasami Hiramatsu return 0; 76821dd9ae5SFranck Bui-Huu err: 76921dd9ae5SFranck Bui-Huu free(name); 77021dd9ae5SFranck Bui-Huu return err; 771631c9defSMasami Hiramatsu } 772631c9defSMasami Hiramatsu 773b7702a21SMasami Hiramatsu /* Check the name is good for event/group */ 774b7702a21SMasami Hiramatsu static bool check_event_name(const char *name) 775b7702a21SMasami Hiramatsu { 776b7702a21SMasami Hiramatsu if (!isalpha(*name) && *name != '_') 777b7702a21SMasami Hiramatsu return false; 778b7702a21SMasami Hiramatsu while (*++name != '\0') { 779b7702a21SMasami Hiramatsu if (!isalpha(*name) && !isdigit(*name) && *name != '_') 780b7702a21SMasami Hiramatsu return false; 781b7702a21SMasami Hiramatsu } 782b7702a21SMasami Hiramatsu return true; 783b7702a21SMasami Hiramatsu } 784b7702a21SMasami Hiramatsu 78550656eecSMasami Hiramatsu /* Parse probepoint definition. */ 786146a1439SMasami Hiramatsu static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) 78750656eecSMasami Hiramatsu { 7884235b045SMasami Hiramatsu struct perf_probe_point *pp = &pev->point; 78950656eecSMasami Hiramatsu char *ptr, *tmp; 79050656eecSMasami Hiramatsu char c, nc = 0; 79150656eecSMasami Hiramatsu /* 79250656eecSMasami Hiramatsu * <Syntax> 7932a9c8c36SMasami Hiramatsu * perf probe [EVENT=]SRC[:LN|;PTN] 7942a9c8c36SMasami Hiramatsu * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] 795af663d75SMasami Hiramatsu * 796af663d75SMasami Hiramatsu * TODO:Group name support 79750656eecSMasami Hiramatsu */ 79850656eecSMasami Hiramatsu 7992a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";=@+%"); 8002a9c8c36SMasami Hiramatsu if (ptr && *ptr == '=') { /* Event name */ 801af663d75SMasami Hiramatsu *ptr = '\0'; 802af663d75SMasami Hiramatsu tmp = ptr + 1; 803146a1439SMasami Hiramatsu if (strchr(arg, ':')) { 804146a1439SMasami Hiramatsu semantic_error("Group name is not supported yet.\n"); 805146a1439SMasami Hiramatsu return -ENOTSUP; 806146a1439SMasami Hiramatsu } 807146a1439SMasami Hiramatsu if (!check_event_name(arg)) { 808b7702a21SMasami Hiramatsu semantic_error("%s is bad for event name -it must " 809146a1439SMasami Hiramatsu "follow C symbol-naming rule.\n", arg); 810146a1439SMasami Hiramatsu return -EINVAL; 811146a1439SMasami Hiramatsu } 81202b95dadSMasami Hiramatsu pev->event = strdup(arg); 81302b95dadSMasami Hiramatsu if (pev->event == NULL) 81402b95dadSMasami Hiramatsu return -ENOMEM; 8154235b045SMasami Hiramatsu pev->group = NULL; 816af663d75SMasami Hiramatsu arg = tmp; 817af663d75SMasami Hiramatsu } 818af663d75SMasami Hiramatsu 8192a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";:+@%"); 82050656eecSMasami Hiramatsu if (ptr) { 82150656eecSMasami Hiramatsu nc = *ptr; 82250656eecSMasami Hiramatsu *ptr++ = '\0'; 82350656eecSMasami Hiramatsu } 82450656eecSMasami Hiramatsu 82502b95dadSMasami Hiramatsu tmp = strdup(arg); 82602b95dadSMasami Hiramatsu if (tmp == NULL) 82702b95dadSMasami Hiramatsu return -ENOMEM; 82802b95dadSMasami Hiramatsu 82950656eecSMasami Hiramatsu /* Check arg is function or file and copy it */ 83002b95dadSMasami Hiramatsu if (strchr(tmp, '.')) /* File */ 83102b95dadSMasami Hiramatsu pp->file = tmp; 83250656eecSMasami Hiramatsu else /* Function */ 83302b95dadSMasami Hiramatsu pp->function = tmp; 83450656eecSMasami Hiramatsu 83550656eecSMasami Hiramatsu /* Parse other options */ 83650656eecSMasami Hiramatsu while (ptr) { 83750656eecSMasami Hiramatsu arg = ptr; 83850656eecSMasami Hiramatsu c = nc; 8392a9c8c36SMasami Hiramatsu if (c == ';') { /* Lazy pattern must be the last part */ 84002b95dadSMasami Hiramatsu pp->lazy_line = strdup(arg); 84102b95dadSMasami Hiramatsu if (pp->lazy_line == NULL) 84202b95dadSMasami Hiramatsu return -ENOMEM; 8432a9c8c36SMasami Hiramatsu break; 8442a9c8c36SMasami Hiramatsu } 8452a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";:+@%"); 84650656eecSMasami Hiramatsu if (ptr) { 84750656eecSMasami Hiramatsu nc = *ptr; 84850656eecSMasami Hiramatsu *ptr++ = '\0'; 84950656eecSMasami Hiramatsu } 85050656eecSMasami Hiramatsu switch (c) { 85150656eecSMasami Hiramatsu case ':': /* Line number */ 85250656eecSMasami Hiramatsu pp->line = strtoul(arg, &tmp, 0); 853146a1439SMasami Hiramatsu if (*tmp != '\0') { 8542a9c8c36SMasami Hiramatsu semantic_error("There is non-digit char" 855146a1439SMasami Hiramatsu " in line number.\n"); 856146a1439SMasami Hiramatsu return -EINVAL; 857146a1439SMasami Hiramatsu } 85850656eecSMasami Hiramatsu break; 85950656eecSMasami Hiramatsu case '+': /* Byte offset from a symbol */ 86050656eecSMasami Hiramatsu pp->offset = strtoul(arg, &tmp, 0); 861146a1439SMasami Hiramatsu if (*tmp != '\0') { 8622a9c8c36SMasami Hiramatsu semantic_error("There is non-digit character" 863146a1439SMasami Hiramatsu " in offset.\n"); 864146a1439SMasami Hiramatsu return -EINVAL; 865146a1439SMasami Hiramatsu } 86650656eecSMasami Hiramatsu break; 86750656eecSMasami Hiramatsu case '@': /* File name */ 868146a1439SMasami Hiramatsu if (pp->file) { 869146a1439SMasami Hiramatsu semantic_error("SRC@SRC is not allowed.\n"); 870146a1439SMasami Hiramatsu return -EINVAL; 871146a1439SMasami Hiramatsu } 87202b95dadSMasami Hiramatsu pp->file = strdup(arg); 87302b95dadSMasami Hiramatsu if (pp->file == NULL) 87402b95dadSMasami Hiramatsu return -ENOMEM; 87550656eecSMasami Hiramatsu break; 87650656eecSMasami Hiramatsu case '%': /* Probe places */ 87750656eecSMasami Hiramatsu if (strcmp(arg, "return") == 0) { 87850656eecSMasami Hiramatsu pp->retprobe = 1; 879146a1439SMasami Hiramatsu } else { /* Others not supported yet */ 880146a1439SMasami Hiramatsu semantic_error("%%%s is not supported.\n", arg); 881146a1439SMasami Hiramatsu return -ENOTSUP; 882146a1439SMasami Hiramatsu } 88350656eecSMasami Hiramatsu break; 884146a1439SMasami Hiramatsu default: /* Buggy case */ 885146a1439SMasami Hiramatsu pr_err("This program has a bug at %s:%d.\n", 886146a1439SMasami Hiramatsu __FILE__, __LINE__); 887146a1439SMasami Hiramatsu return -ENOTSUP; 88850656eecSMasami Hiramatsu break; 88950656eecSMasami Hiramatsu } 89050656eecSMasami Hiramatsu } 89150656eecSMasami Hiramatsu 89250656eecSMasami Hiramatsu /* Exclusion check */ 893146a1439SMasami Hiramatsu if (pp->lazy_line && pp->line) { 8940e43e5d2SMasami Hiramatsu semantic_error("Lazy pattern can't be used with" 8950e43e5d2SMasami Hiramatsu " line number.\n"); 896146a1439SMasami Hiramatsu return -EINVAL; 897146a1439SMasami Hiramatsu } 8982a9c8c36SMasami Hiramatsu 899146a1439SMasami Hiramatsu if (pp->lazy_line && pp->offset) { 9000e43e5d2SMasami Hiramatsu semantic_error("Lazy pattern can't be used with offset.\n"); 901146a1439SMasami Hiramatsu return -EINVAL; 902146a1439SMasami Hiramatsu } 9032a9c8c36SMasami Hiramatsu 904146a1439SMasami Hiramatsu if (pp->line && pp->offset) { 9050e43e5d2SMasami Hiramatsu semantic_error("Offset can't be used with line number.\n"); 906146a1439SMasami Hiramatsu return -EINVAL; 907146a1439SMasami Hiramatsu } 90850656eecSMasami Hiramatsu 909146a1439SMasami Hiramatsu if (!pp->line && !pp->lazy_line && pp->file && !pp->function) { 9102a9c8c36SMasami Hiramatsu semantic_error("File always requires line number or " 9110e43e5d2SMasami Hiramatsu "lazy pattern.\n"); 912146a1439SMasami Hiramatsu return -EINVAL; 913146a1439SMasami Hiramatsu } 91450656eecSMasami Hiramatsu 915146a1439SMasami Hiramatsu if (pp->offset && !pp->function) { 9160e43e5d2SMasami Hiramatsu semantic_error("Offset requires an entry function.\n"); 917146a1439SMasami Hiramatsu return -EINVAL; 918146a1439SMasami Hiramatsu } 91950656eecSMasami Hiramatsu 920146a1439SMasami Hiramatsu if (pp->retprobe && !pp->function) { 9210e43e5d2SMasami Hiramatsu semantic_error("Return probe requires an entry function.\n"); 922146a1439SMasami Hiramatsu return -EINVAL; 923146a1439SMasami Hiramatsu } 92450656eecSMasami Hiramatsu 925146a1439SMasami Hiramatsu if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { 9262a9c8c36SMasami Hiramatsu semantic_error("Offset/Line/Lazy pattern can't be used with " 9270e43e5d2SMasami Hiramatsu "return probe.\n"); 928146a1439SMasami Hiramatsu return -EINVAL; 929146a1439SMasami Hiramatsu } 93050656eecSMasami Hiramatsu 9314235b045SMasami Hiramatsu pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n", 9322a9c8c36SMasami Hiramatsu pp->function, pp->file, pp->line, pp->offset, pp->retprobe, 9332a9c8c36SMasami Hiramatsu pp->lazy_line); 934146a1439SMasami Hiramatsu return 0; 93550656eecSMasami Hiramatsu } 93650656eecSMasami Hiramatsu 9377df2f329SMasami Hiramatsu /* Parse perf-probe event argument */ 938146a1439SMasami Hiramatsu static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) 9397df2f329SMasami Hiramatsu { 940b2a3c12bSMasami Hiramatsu char *tmp, *goodname; 9417df2f329SMasami Hiramatsu struct perf_probe_arg_field **fieldp; 9427df2f329SMasami Hiramatsu 9437df2f329SMasami Hiramatsu pr_debug("parsing arg: %s into ", str); 9447df2f329SMasami Hiramatsu 94548481938SMasami Hiramatsu tmp = strchr(str, '='); 94648481938SMasami Hiramatsu if (tmp) { 94702b95dadSMasami Hiramatsu arg->name = strndup(str, tmp - str); 94802b95dadSMasami Hiramatsu if (arg->name == NULL) 94902b95dadSMasami Hiramatsu return -ENOMEM; 95011a1ca35SMasami Hiramatsu pr_debug("name:%s ", arg->name); 95148481938SMasami Hiramatsu str = tmp + 1; 95248481938SMasami Hiramatsu } 95348481938SMasami Hiramatsu 95411a1ca35SMasami Hiramatsu tmp = strchr(str, ':'); 95511a1ca35SMasami Hiramatsu if (tmp) { /* Type setting */ 95611a1ca35SMasami Hiramatsu *tmp = '\0'; 95702b95dadSMasami Hiramatsu arg->type = strdup(tmp + 1); 95802b95dadSMasami Hiramatsu if (arg->type == NULL) 95902b95dadSMasami Hiramatsu return -ENOMEM; 96011a1ca35SMasami Hiramatsu pr_debug("type:%s ", arg->type); 96111a1ca35SMasami Hiramatsu } 96211a1ca35SMasami Hiramatsu 963b2a3c12bSMasami Hiramatsu tmp = strpbrk(str, "-.["); 9647df2f329SMasami Hiramatsu if (!is_c_varname(str) || !tmp) { 9657df2f329SMasami Hiramatsu /* A variable, register, symbol or special value */ 96602b95dadSMasami Hiramatsu arg->var = strdup(str); 96702b95dadSMasami Hiramatsu if (arg->var == NULL) 96802b95dadSMasami Hiramatsu return -ENOMEM; 96948481938SMasami Hiramatsu pr_debug("%s\n", arg->var); 970146a1439SMasami Hiramatsu return 0; 9717df2f329SMasami Hiramatsu } 9727df2f329SMasami Hiramatsu 973b2a3c12bSMasami Hiramatsu /* Structure fields or array element */ 97402b95dadSMasami Hiramatsu arg->var = strndup(str, tmp - str); 97502b95dadSMasami Hiramatsu if (arg->var == NULL) 97602b95dadSMasami Hiramatsu return -ENOMEM; 977b2a3c12bSMasami Hiramatsu goodname = arg->var; 97848481938SMasami Hiramatsu pr_debug("%s, ", arg->var); 9797df2f329SMasami Hiramatsu fieldp = &arg->field; 9807df2f329SMasami Hiramatsu 9817df2f329SMasami Hiramatsu do { 982e334016fSMasami Hiramatsu *fieldp = zalloc(sizeof(struct perf_probe_arg_field)); 983e334016fSMasami Hiramatsu if (*fieldp == NULL) 984e334016fSMasami Hiramatsu return -ENOMEM; 985b2a3c12bSMasami Hiramatsu if (*tmp == '[') { /* Array */ 986b2a3c12bSMasami Hiramatsu str = tmp; 987b2a3c12bSMasami Hiramatsu (*fieldp)->index = strtol(str + 1, &tmp, 0); 988b2a3c12bSMasami Hiramatsu (*fieldp)->ref = true; 989b2a3c12bSMasami Hiramatsu if (*tmp != ']' || tmp == str + 1) { 990b2a3c12bSMasami Hiramatsu semantic_error("Array index must be a" 991b2a3c12bSMasami Hiramatsu " number.\n"); 992b2a3c12bSMasami Hiramatsu return -EINVAL; 993b2a3c12bSMasami Hiramatsu } 994b2a3c12bSMasami Hiramatsu tmp++; 995b2a3c12bSMasami Hiramatsu if (*tmp == '\0') 996b2a3c12bSMasami Hiramatsu tmp = NULL; 997b2a3c12bSMasami Hiramatsu } else { /* Structure */ 9987df2f329SMasami Hiramatsu if (*tmp == '.') { 9997df2f329SMasami Hiramatsu str = tmp + 1; 10007df2f329SMasami Hiramatsu (*fieldp)->ref = false; 10017df2f329SMasami Hiramatsu } else if (tmp[1] == '>') { 10027df2f329SMasami Hiramatsu str = tmp + 2; 10037df2f329SMasami Hiramatsu (*fieldp)->ref = true; 1004146a1439SMasami Hiramatsu } else { 1005b2a3c12bSMasami Hiramatsu semantic_error("Argument parse error: %s\n", 1006b2a3c12bSMasami Hiramatsu str); 1007146a1439SMasami Hiramatsu return -EINVAL; 1008146a1439SMasami Hiramatsu } 1009b2a3c12bSMasami Hiramatsu tmp = strpbrk(str, "-.["); 1010b2a3c12bSMasami Hiramatsu } 10117df2f329SMasami Hiramatsu if (tmp) { 101202b95dadSMasami Hiramatsu (*fieldp)->name = strndup(str, tmp - str); 101302b95dadSMasami Hiramatsu if ((*fieldp)->name == NULL) 101402b95dadSMasami Hiramatsu return -ENOMEM; 1015b2a3c12bSMasami Hiramatsu if (*str != '[') 1016b2a3c12bSMasami Hiramatsu goodname = (*fieldp)->name; 10177df2f329SMasami Hiramatsu pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); 10187df2f329SMasami Hiramatsu fieldp = &(*fieldp)->next; 10197df2f329SMasami Hiramatsu } 10207df2f329SMasami Hiramatsu } while (tmp); 102102b95dadSMasami Hiramatsu (*fieldp)->name = strdup(str); 102202b95dadSMasami Hiramatsu if ((*fieldp)->name == NULL) 102302b95dadSMasami Hiramatsu return -ENOMEM; 1024b2a3c12bSMasami Hiramatsu if (*str != '[') 1025b2a3c12bSMasami Hiramatsu goodname = (*fieldp)->name; 10267df2f329SMasami Hiramatsu pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); 1027df0faf4bSMasami Hiramatsu 1028b2a3c12bSMasami Hiramatsu /* If no name is specified, set the last field name (not array index)*/ 102902b95dadSMasami Hiramatsu if (!arg->name) { 1030b2a3c12bSMasami Hiramatsu arg->name = strdup(goodname); 103102b95dadSMasami Hiramatsu if (arg->name == NULL) 103202b95dadSMasami Hiramatsu return -ENOMEM; 103302b95dadSMasami Hiramatsu } 1034146a1439SMasami Hiramatsu return 0; 10357df2f329SMasami Hiramatsu } 10367df2f329SMasami Hiramatsu 10374235b045SMasami Hiramatsu /* Parse perf-probe event command */ 1038146a1439SMasami Hiramatsu int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) 103950656eecSMasami Hiramatsu { 1040e1c01d61SMasami Hiramatsu char **argv; 1041146a1439SMasami Hiramatsu int argc, i, ret = 0; 1042fac13fd5SMasami Hiramatsu 10434235b045SMasami Hiramatsu argv = argv_split(cmd, &argc); 1044146a1439SMasami Hiramatsu if (!argv) { 1045146a1439SMasami Hiramatsu pr_debug("Failed to split arguments.\n"); 1046146a1439SMasami Hiramatsu return -ENOMEM; 1047146a1439SMasami Hiramatsu } 1048146a1439SMasami Hiramatsu if (argc - 1 > MAX_PROBE_ARGS) { 1049146a1439SMasami Hiramatsu semantic_error("Too many probe arguments (%d).\n", argc - 1); 1050146a1439SMasami Hiramatsu ret = -ERANGE; 1051146a1439SMasami Hiramatsu goto out; 1052146a1439SMasami Hiramatsu } 105350656eecSMasami Hiramatsu /* Parse probe point */ 1054146a1439SMasami Hiramatsu ret = parse_perf_probe_point(argv[0], pev); 1055146a1439SMasami Hiramatsu if (ret < 0) 1056146a1439SMasami Hiramatsu goto out; 105750656eecSMasami Hiramatsu 1058e1c01d61SMasami Hiramatsu /* Copy arguments and ensure return probe has no C argument */ 10594235b045SMasami Hiramatsu pev->nargs = argc - 1; 1060e334016fSMasami Hiramatsu pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); 1061e334016fSMasami Hiramatsu if (pev->args == NULL) { 1062e334016fSMasami Hiramatsu ret = -ENOMEM; 1063e334016fSMasami Hiramatsu goto out; 1064e334016fSMasami Hiramatsu } 1065146a1439SMasami Hiramatsu for (i = 0; i < pev->nargs && ret >= 0; i++) { 1066146a1439SMasami Hiramatsu ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]); 1067146a1439SMasami Hiramatsu if (ret >= 0 && 1068146a1439SMasami Hiramatsu is_c_varname(pev->args[i].var) && pev->point.retprobe) { 10694235b045SMasami Hiramatsu semantic_error("You can't specify local variable for" 1070146a1439SMasami Hiramatsu " kretprobe.\n"); 1071146a1439SMasami Hiramatsu ret = -EINVAL; 1072e1c01d61SMasami Hiramatsu } 1073146a1439SMasami Hiramatsu } 1074146a1439SMasami Hiramatsu out: 1075e1c01d61SMasami Hiramatsu argv_free(argv); 1076146a1439SMasami Hiramatsu 1077146a1439SMasami Hiramatsu return ret; 107850656eecSMasami Hiramatsu } 107950656eecSMasami Hiramatsu 10804235b045SMasami Hiramatsu /* Return true if this perf_probe_event requires debuginfo */ 10814235b045SMasami Hiramatsu bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) 10824de189feSMasami Hiramatsu { 10834235b045SMasami Hiramatsu int i; 10844235b045SMasami Hiramatsu 10854235b045SMasami Hiramatsu if (pev->point.file || pev->point.line || pev->point.lazy_line) 10864235b045SMasami Hiramatsu return true; 10874235b045SMasami Hiramatsu 10884235b045SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) 108948481938SMasami Hiramatsu if (is_c_varname(pev->args[i].var)) 10904235b045SMasami Hiramatsu return true; 10914235b045SMasami Hiramatsu 10924235b045SMasami Hiramatsu return false; 10934235b045SMasami Hiramatsu } 10944235b045SMasami Hiramatsu 10950e60836bSSrikar Dronamraju /* Parse probe_events event into struct probe_point */ 10960e60836bSSrikar Dronamraju static int parse_probe_trace_command(const char *cmd, 10970e60836bSSrikar Dronamraju struct probe_trace_event *tev) 10984235b045SMasami Hiramatsu { 10990e60836bSSrikar Dronamraju struct probe_trace_point *tp = &tev->point; 11004de189feSMasami Hiramatsu char pr; 11014de189feSMasami Hiramatsu char *p; 11024de189feSMasami Hiramatsu int ret, i, argc; 11034de189feSMasami Hiramatsu char **argv; 11044de189feSMasami Hiramatsu 11050e60836bSSrikar Dronamraju pr_debug("Parsing probe_events: %s\n", cmd); 11064235b045SMasami Hiramatsu argv = argv_split(cmd, &argc); 1107146a1439SMasami Hiramatsu if (!argv) { 1108146a1439SMasami Hiramatsu pr_debug("Failed to split arguments.\n"); 1109146a1439SMasami Hiramatsu return -ENOMEM; 1110146a1439SMasami Hiramatsu } 1111146a1439SMasami Hiramatsu if (argc < 2) { 1112146a1439SMasami Hiramatsu semantic_error("Too few probe arguments.\n"); 1113146a1439SMasami Hiramatsu ret = -ERANGE; 1114146a1439SMasami Hiramatsu goto out; 1115146a1439SMasami Hiramatsu } 11164de189feSMasami Hiramatsu 11174de189feSMasami Hiramatsu /* Scan event and group name. */ 111893aaa45aSLiming Wang ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", 11194235b045SMasami Hiramatsu &pr, (float *)(void *)&tev->group, 11204235b045SMasami Hiramatsu (float *)(void *)&tev->event); 1121146a1439SMasami Hiramatsu if (ret != 3) { 1122146a1439SMasami Hiramatsu semantic_error("Failed to parse event name: %s\n", argv[0]); 1123146a1439SMasami Hiramatsu ret = -EINVAL; 1124146a1439SMasami Hiramatsu goto out; 1125146a1439SMasami Hiramatsu } 11264235b045SMasami Hiramatsu pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr); 11274de189feSMasami Hiramatsu 11284235b045SMasami Hiramatsu tp->retprobe = (pr == 'r'); 11294de189feSMasami Hiramatsu 1130190b57fcSMasami Hiramatsu /* Scan module name(if there), function name and offset */ 1131190b57fcSMasami Hiramatsu p = strchr(argv[1], ':'); 1132190b57fcSMasami Hiramatsu if (p) { 1133190b57fcSMasami Hiramatsu tp->module = strndup(argv[1], p - argv[1]); 1134190b57fcSMasami Hiramatsu p++; 1135190b57fcSMasami Hiramatsu } else 1136190b57fcSMasami Hiramatsu p = argv[1]; 1137190b57fcSMasami Hiramatsu ret = sscanf(p, "%a[^+]+%lu", (float *)(void *)&tp->symbol, 11384235b045SMasami Hiramatsu &tp->offset); 11394de189feSMasami Hiramatsu if (ret == 1) 11404235b045SMasami Hiramatsu tp->offset = 0; 11414de189feSMasami Hiramatsu 11424235b045SMasami Hiramatsu tev->nargs = argc - 2; 11430e60836bSSrikar Dronamraju tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1144e334016fSMasami Hiramatsu if (tev->args == NULL) { 1145e334016fSMasami Hiramatsu ret = -ENOMEM; 1146e334016fSMasami Hiramatsu goto out; 1147e334016fSMasami Hiramatsu } 11484235b045SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 11494de189feSMasami Hiramatsu p = strchr(argv[i + 2], '='); 11504de189feSMasami Hiramatsu if (p) /* We don't need which register is assigned. */ 11514235b045SMasami Hiramatsu *p++ = '\0'; 11524235b045SMasami Hiramatsu else 11534235b045SMasami Hiramatsu p = argv[i + 2]; 115402b95dadSMasami Hiramatsu tev->args[i].name = strdup(argv[i + 2]); 11554235b045SMasami Hiramatsu /* TODO: parse regs and offset */ 115602b95dadSMasami Hiramatsu tev->args[i].value = strdup(p); 115702b95dadSMasami Hiramatsu if (tev->args[i].name == NULL || tev->args[i].value == NULL) { 115802b95dadSMasami Hiramatsu ret = -ENOMEM; 115902b95dadSMasami Hiramatsu goto out; 116002b95dadSMasami Hiramatsu } 11614de189feSMasami Hiramatsu } 1162146a1439SMasami Hiramatsu ret = 0; 1163146a1439SMasami Hiramatsu out: 11644de189feSMasami Hiramatsu argv_free(argv); 1165146a1439SMasami Hiramatsu return ret; 11664de189feSMasami Hiramatsu } 11674de189feSMasami Hiramatsu 11687df2f329SMasami Hiramatsu /* Compose only probe arg */ 11697df2f329SMasami Hiramatsu int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) 11707df2f329SMasami Hiramatsu { 11717df2f329SMasami Hiramatsu struct perf_probe_arg_field *field = pa->field; 11727df2f329SMasami Hiramatsu int ret; 11737df2f329SMasami Hiramatsu char *tmp = buf; 11747df2f329SMasami Hiramatsu 117548481938SMasami Hiramatsu if (pa->name && pa->var) 117648481938SMasami Hiramatsu ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var); 117748481938SMasami Hiramatsu else 117848481938SMasami Hiramatsu ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var); 11797df2f329SMasami Hiramatsu if (ret <= 0) 11807df2f329SMasami Hiramatsu goto error; 11817df2f329SMasami Hiramatsu tmp += ret; 11827df2f329SMasami Hiramatsu len -= ret; 11837df2f329SMasami Hiramatsu 11847df2f329SMasami Hiramatsu while (field) { 1185b2a3c12bSMasami Hiramatsu if (field->name[0] == '[') 1186b2a3c12bSMasami Hiramatsu ret = e_snprintf(tmp, len, "%s", field->name); 1187b2a3c12bSMasami Hiramatsu else 1188b2a3c12bSMasami Hiramatsu ret = e_snprintf(tmp, len, "%s%s", 1189b2a3c12bSMasami Hiramatsu field->ref ? "->" : ".", field->name); 11907df2f329SMasami Hiramatsu if (ret <= 0) 11917df2f329SMasami Hiramatsu goto error; 11927df2f329SMasami Hiramatsu tmp += ret; 11937df2f329SMasami Hiramatsu len -= ret; 11947df2f329SMasami Hiramatsu field = field->next; 11957df2f329SMasami Hiramatsu } 119611a1ca35SMasami Hiramatsu 119711a1ca35SMasami Hiramatsu if (pa->type) { 119811a1ca35SMasami Hiramatsu ret = e_snprintf(tmp, len, ":%s", pa->type); 119911a1ca35SMasami Hiramatsu if (ret <= 0) 120011a1ca35SMasami Hiramatsu goto error; 120111a1ca35SMasami Hiramatsu tmp += ret; 120211a1ca35SMasami Hiramatsu len -= ret; 120311a1ca35SMasami Hiramatsu } 120411a1ca35SMasami Hiramatsu 12057df2f329SMasami Hiramatsu return tmp - buf; 12067df2f329SMasami Hiramatsu error: 12070e43e5d2SMasami Hiramatsu pr_debug("Failed to synthesize perf probe argument: %s\n", 1208146a1439SMasami Hiramatsu strerror(-ret)); 1209146a1439SMasami Hiramatsu return ret; 12107df2f329SMasami Hiramatsu } 12117df2f329SMasami Hiramatsu 12124235b045SMasami Hiramatsu /* Compose only probe point (not argument) */ 12134235b045SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp) 121450656eecSMasami Hiramatsu { 1215fb1587d8SMasami Hiramatsu char *buf, *tmp; 1216fb1587d8SMasami Hiramatsu char offs[32] = "", line[32] = "", file[32] = ""; 1217fb1587d8SMasami Hiramatsu int ret, len; 121850656eecSMasami Hiramatsu 1219e334016fSMasami Hiramatsu buf = zalloc(MAX_CMDLEN); 1220e334016fSMasami Hiramatsu if (buf == NULL) { 1221e334016fSMasami Hiramatsu ret = -ENOMEM; 1222e334016fSMasami Hiramatsu goto error; 1223e334016fSMasami Hiramatsu } 12244de189feSMasami Hiramatsu if (pp->offset) { 1225fb1587d8SMasami Hiramatsu ret = e_snprintf(offs, 32, "+%lu", pp->offset); 12264de189feSMasami Hiramatsu if (ret <= 0) 12274de189feSMasami Hiramatsu goto error; 12284de189feSMasami Hiramatsu } 12294de189feSMasami Hiramatsu if (pp->line) { 1230fb1587d8SMasami Hiramatsu ret = e_snprintf(line, 32, ":%d", pp->line); 1231fb1587d8SMasami Hiramatsu if (ret <= 0) 1232fb1587d8SMasami Hiramatsu goto error; 1233fb1587d8SMasami Hiramatsu } 1234fb1587d8SMasami Hiramatsu if (pp->file) { 123532ae2adeSFranck Bui-Huu tmp = pp->file; 123632ae2adeSFranck Bui-Huu len = strlen(tmp); 123732ae2adeSFranck Bui-Huu if (len > 30) { 123832ae2adeSFranck Bui-Huu tmp = strchr(pp->file + len - 30, '/'); 123932ae2adeSFranck Bui-Huu tmp = tmp ? tmp + 1 : pp->file + len - 30; 124032ae2adeSFranck Bui-Huu } 124132ae2adeSFranck Bui-Huu ret = e_snprintf(file, 32, "@%s", tmp); 12424de189feSMasami Hiramatsu if (ret <= 0) 12434de189feSMasami Hiramatsu goto error; 12444de189feSMasami Hiramatsu } 12454de189feSMasami Hiramatsu 12464de189feSMasami Hiramatsu if (pp->function) 1247fb1587d8SMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function, 1248fb1587d8SMasami Hiramatsu offs, pp->retprobe ? "%return" : "", line, 1249fb1587d8SMasami Hiramatsu file); 12504de189feSMasami Hiramatsu else 1251fb1587d8SMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line); 12524235b045SMasami Hiramatsu if (ret <= 0) 12534235b045SMasami Hiramatsu goto error; 12544235b045SMasami Hiramatsu 12554235b045SMasami Hiramatsu return buf; 12564235b045SMasami Hiramatsu error: 12570e43e5d2SMasami Hiramatsu pr_debug("Failed to synthesize perf probe point: %s\n", 1258146a1439SMasami Hiramatsu strerror(-ret)); 1259e334016fSMasami Hiramatsu if (buf) 1260146a1439SMasami Hiramatsu free(buf); 1261146a1439SMasami Hiramatsu return NULL; 12624235b045SMasami Hiramatsu } 12634235b045SMasami Hiramatsu 12644235b045SMasami Hiramatsu #if 0 12654235b045SMasami Hiramatsu char *synthesize_perf_probe_command(struct perf_probe_event *pev) 12664235b045SMasami Hiramatsu { 12674235b045SMasami Hiramatsu char *buf; 12684235b045SMasami Hiramatsu int i, len, ret; 12694235b045SMasami Hiramatsu 12704235b045SMasami Hiramatsu buf = synthesize_perf_probe_point(&pev->point); 12714235b045SMasami Hiramatsu if (!buf) 12724235b045SMasami Hiramatsu return NULL; 12734235b045SMasami Hiramatsu 12744235b045SMasami Hiramatsu len = strlen(buf); 12754235b045SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) { 12764235b045SMasami Hiramatsu ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 12774235b045SMasami Hiramatsu pev->args[i].name); 12787ef17aafSMasami Hiramatsu if (ret <= 0) { 12794235b045SMasami Hiramatsu free(buf); 12804235b045SMasami Hiramatsu return NULL; 12817ef17aafSMasami Hiramatsu } 12824235b045SMasami Hiramatsu len += ret; 12837ef17aafSMasami Hiramatsu } 128450656eecSMasami Hiramatsu 12854235b045SMasami Hiramatsu return buf; 12864235b045SMasami Hiramatsu } 12874235b045SMasami Hiramatsu #endif 12884235b045SMasami Hiramatsu 12890e60836bSSrikar Dronamraju static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, 12904235b045SMasami Hiramatsu char **buf, size_t *buflen, 12914235b045SMasami Hiramatsu int depth) 12927ef17aafSMasami Hiramatsu { 12934235b045SMasami Hiramatsu int ret; 12944235b045SMasami Hiramatsu if (ref->next) { 12950e60836bSSrikar Dronamraju depth = __synthesize_probe_trace_arg_ref(ref->next, buf, 12964235b045SMasami Hiramatsu buflen, depth + 1); 12974235b045SMasami Hiramatsu if (depth < 0) 12984235b045SMasami Hiramatsu goto out; 12994235b045SMasami Hiramatsu } 13004235b045SMasami Hiramatsu 13014235b045SMasami Hiramatsu ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset); 13024235b045SMasami Hiramatsu if (ret < 0) 13034235b045SMasami Hiramatsu depth = ret; 13044235b045SMasami Hiramatsu else { 13054235b045SMasami Hiramatsu *buf += ret; 13064235b045SMasami Hiramatsu *buflen -= ret; 13074235b045SMasami Hiramatsu } 13084235b045SMasami Hiramatsu out: 13094235b045SMasami Hiramatsu return depth; 13104235b045SMasami Hiramatsu 13114235b045SMasami Hiramatsu } 13124235b045SMasami Hiramatsu 13130e60836bSSrikar Dronamraju static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, 13144235b045SMasami Hiramatsu char *buf, size_t buflen) 13154235b045SMasami Hiramatsu { 13160e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref = arg->ref; 13174235b045SMasami Hiramatsu int ret, depth = 0; 13184235b045SMasami Hiramatsu char *tmp = buf; 13194235b045SMasami Hiramatsu 13204235b045SMasami Hiramatsu /* Argument name or separator */ 13214235b045SMasami Hiramatsu if (arg->name) 13224235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, " %s=", arg->name); 13234235b045SMasami Hiramatsu else 13244235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, " "); 13254235b045SMasami Hiramatsu if (ret < 0) 13264235b045SMasami Hiramatsu return ret; 13274235b045SMasami Hiramatsu buf += ret; 13284235b045SMasami Hiramatsu buflen -= ret; 13294235b045SMasami Hiramatsu 1330b7dcb857SMasami Hiramatsu /* Special case: @XXX */ 1331b7dcb857SMasami Hiramatsu if (arg->value[0] == '@' && arg->ref) 1332b7dcb857SMasami Hiramatsu ref = ref->next; 1333b7dcb857SMasami Hiramatsu 13344235b045SMasami Hiramatsu /* Dereferencing arguments */ 1335b7dcb857SMasami Hiramatsu if (ref) { 13360e60836bSSrikar Dronamraju depth = __synthesize_probe_trace_arg_ref(ref, &buf, 13374235b045SMasami Hiramatsu &buflen, 1); 13384235b045SMasami Hiramatsu if (depth < 0) 13394235b045SMasami Hiramatsu return depth; 13404235b045SMasami Hiramatsu } 13414235b045SMasami Hiramatsu 13424235b045SMasami Hiramatsu /* Print argument value */ 1343b7dcb857SMasami Hiramatsu if (arg->value[0] == '@' && arg->ref) 1344b7dcb857SMasami Hiramatsu ret = e_snprintf(buf, buflen, "%s%+ld", arg->value, 1345b7dcb857SMasami Hiramatsu arg->ref->offset); 1346b7dcb857SMasami Hiramatsu else 13474235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, "%s", arg->value); 13484235b045SMasami Hiramatsu if (ret < 0) 13494235b045SMasami Hiramatsu return ret; 13504235b045SMasami Hiramatsu buf += ret; 13514235b045SMasami Hiramatsu buflen -= ret; 13524235b045SMasami Hiramatsu 13534235b045SMasami Hiramatsu /* Closing */ 13544235b045SMasami Hiramatsu while (depth--) { 13554235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, ")"); 13564235b045SMasami Hiramatsu if (ret < 0) 13574235b045SMasami Hiramatsu return ret; 13584235b045SMasami Hiramatsu buf += ret; 13594235b045SMasami Hiramatsu buflen -= ret; 13604235b045SMasami Hiramatsu } 13614984912eSMasami Hiramatsu /* Print argument type */ 13624984912eSMasami Hiramatsu if (arg->type) { 13634984912eSMasami Hiramatsu ret = e_snprintf(buf, buflen, ":%s", arg->type); 13644984912eSMasami Hiramatsu if (ret <= 0) 13654984912eSMasami Hiramatsu return ret; 13664984912eSMasami Hiramatsu buf += ret; 13674984912eSMasami Hiramatsu } 13684235b045SMasami Hiramatsu 13694235b045SMasami Hiramatsu return buf - tmp; 13704235b045SMasami Hiramatsu } 13714235b045SMasami Hiramatsu 13720e60836bSSrikar Dronamraju char *synthesize_probe_trace_command(struct probe_trace_event *tev) 13734235b045SMasami Hiramatsu { 13740e60836bSSrikar Dronamraju struct probe_trace_point *tp = &tev->point; 13757ef17aafSMasami Hiramatsu char *buf; 13767ef17aafSMasami Hiramatsu int i, len, ret; 13777ef17aafSMasami Hiramatsu 1378e334016fSMasami Hiramatsu buf = zalloc(MAX_CMDLEN); 1379e334016fSMasami Hiramatsu if (buf == NULL) 1380e334016fSMasami Hiramatsu return NULL; 1381e334016fSMasami Hiramatsu 1382225466f1SSrikar Dronamraju if (tev->uprobes) 1383225466f1SSrikar Dronamraju len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s", 1384225466f1SSrikar Dronamraju tp->retprobe ? 'r' : 'p', 1385225466f1SSrikar Dronamraju tev->group, tev->event, 1386225466f1SSrikar Dronamraju tp->module, tp->symbol); 1387225466f1SSrikar Dronamraju else 1388190b57fcSMasami Hiramatsu len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", 13894235b045SMasami Hiramatsu tp->retprobe ? 'r' : 'p', 13904235b045SMasami Hiramatsu tev->group, tev->event, 1391190b57fcSMasami Hiramatsu tp->module ?: "", tp->module ? ":" : "", 13924235b045SMasami Hiramatsu tp->symbol, tp->offset); 1393225466f1SSrikar Dronamraju 13944235b045SMasami Hiramatsu if (len <= 0) 13954235b045SMasami Hiramatsu goto error; 13967ef17aafSMasami Hiramatsu 13974235b045SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 13980e60836bSSrikar Dronamraju ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, 13994235b045SMasami Hiramatsu MAX_CMDLEN - len); 14004de189feSMasami Hiramatsu if (ret <= 0) 140150656eecSMasami Hiramatsu goto error; 140250656eecSMasami Hiramatsu len += ret; 140350656eecSMasami Hiramatsu } 140450656eecSMasami Hiramatsu 14054235b045SMasami Hiramatsu return buf; 140650656eecSMasami Hiramatsu error: 14074235b045SMasami Hiramatsu free(buf); 14084235b045SMasami Hiramatsu return NULL; 140950656eecSMasami Hiramatsu } 141050656eecSMasami Hiramatsu 14110e60836bSSrikar Dronamraju static int convert_to_perf_probe_event(struct probe_trace_event *tev, 1412225466f1SSrikar Dronamraju struct perf_probe_event *pev, bool is_kprobe) 14134de189feSMasami Hiramatsu { 141402b95dadSMasami Hiramatsu char buf[64] = ""; 1415146a1439SMasami Hiramatsu int i, ret; 14164de189feSMasami Hiramatsu 14174b4da7f7SMasami Hiramatsu /* Convert event/group name */ 141802b95dadSMasami Hiramatsu pev->event = strdup(tev->event); 141902b95dadSMasami Hiramatsu pev->group = strdup(tev->group); 142002b95dadSMasami Hiramatsu if (pev->event == NULL || pev->group == NULL) 142102b95dadSMasami Hiramatsu return -ENOMEM; 1422fb1587d8SMasami Hiramatsu 14234b4da7f7SMasami Hiramatsu /* Convert trace_point to probe_point */ 1424225466f1SSrikar Dronamraju if (is_kprobe) 14250e60836bSSrikar Dronamraju ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); 1426225466f1SSrikar Dronamraju else 1427225466f1SSrikar Dronamraju ret = convert_to_perf_probe_point(&tev->point, &pev->point); 1428225466f1SSrikar Dronamraju 1429146a1439SMasami Hiramatsu if (ret < 0) 1430146a1439SMasami Hiramatsu return ret; 14314b4da7f7SMasami Hiramatsu 14324235b045SMasami Hiramatsu /* Convert trace_arg to probe_arg */ 14334235b045SMasami Hiramatsu pev->nargs = tev->nargs; 1434e334016fSMasami Hiramatsu pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); 1435e334016fSMasami Hiramatsu if (pev->args == NULL) 1436e334016fSMasami Hiramatsu return -ENOMEM; 143702b95dadSMasami Hiramatsu for (i = 0; i < tev->nargs && ret >= 0; i++) { 14384235b045SMasami Hiramatsu if (tev->args[i].name) 143902b95dadSMasami Hiramatsu pev->args[i].name = strdup(tev->args[i].name); 14404235b045SMasami Hiramatsu else { 14410e60836bSSrikar Dronamraju ret = synthesize_probe_trace_arg(&tev->args[i], 1442146a1439SMasami Hiramatsu buf, 64); 144302b95dadSMasami Hiramatsu pev->args[i].name = strdup(buf); 144402b95dadSMasami Hiramatsu } 144502b95dadSMasami Hiramatsu if (pev->args[i].name == NULL && ret >= 0) 144602b95dadSMasami Hiramatsu ret = -ENOMEM; 14474de189feSMasami Hiramatsu } 1448146a1439SMasami Hiramatsu 1449146a1439SMasami Hiramatsu if (ret < 0) 1450146a1439SMasami Hiramatsu clear_perf_probe_event(pev); 1451146a1439SMasami Hiramatsu 1452146a1439SMasami Hiramatsu return ret; 14534235b045SMasami Hiramatsu } 14544de189feSMasami Hiramatsu 14554235b045SMasami Hiramatsu void clear_perf_probe_event(struct perf_probe_event *pev) 14564235b045SMasami Hiramatsu { 14574235b045SMasami Hiramatsu struct perf_probe_point *pp = &pev->point; 14587df2f329SMasami Hiramatsu struct perf_probe_arg_field *field, *next; 14594235b045SMasami Hiramatsu int i; 14604de189feSMasami Hiramatsu 14614235b045SMasami Hiramatsu if (pev->event) 14624235b045SMasami Hiramatsu free(pev->event); 14634235b045SMasami Hiramatsu if (pev->group) 14644235b045SMasami Hiramatsu free(pev->group); 14654235b045SMasami Hiramatsu if (pp->file) 14664235b045SMasami Hiramatsu free(pp->file); 14674235b045SMasami Hiramatsu if (pp->function) 14684235b045SMasami Hiramatsu free(pp->function); 14694235b045SMasami Hiramatsu if (pp->lazy_line) 14704235b045SMasami Hiramatsu free(pp->lazy_line); 14717df2f329SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) { 14724235b045SMasami Hiramatsu if (pev->args[i].name) 14734235b045SMasami Hiramatsu free(pev->args[i].name); 147448481938SMasami Hiramatsu if (pev->args[i].var) 147548481938SMasami Hiramatsu free(pev->args[i].var); 147611a1ca35SMasami Hiramatsu if (pev->args[i].type) 147711a1ca35SMasami Hiramatsu free(pev->args[i].type); 14787df2f329SMasami Hiramatsu field = pev->args[i].field; 14797df2f329SMasami Hiramatsu while (field) { 14807df2f329SMasami Hiramatsu next = field->next; 14817df2f329SMasami Hiramatsu if (field->name) 14827df2f329SMasami Hiramatsu free(field->name); 14837df2f329SMasami Hiramatsu free(field); 14847df2f329SMasami Hiramatsu field = next; 14857df2f329SMasami Hiramatsu } 14867df2f329SMasami Hiramatsu } 14874235b045SMasami Hiramatsu if (pev->args) 14884235b045SMasami Hiramatsu free(pev->args); 14894235b045SMasami Hiramatsu memset(pev, 0, sizeof(*pev)); 14904235b045SMasami Hiramatsu } 14914235b045SMasami Hiramatsu 14920e60836bSSrikar Dronamraju static void clear_probe_trace_event(struct probe_trace_event *tev) 14934235b045SMasami Hiramatsu { 14940e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref, *next; 14954235b045SMasami Hiramatsu int i; 14964235b045SMasami Hiramatsu 14974235b045SMasami Hiramatsu if (tev->event) 14984235b045SMasami Hiramatsu free(tev->event); 14994235b045SMasami Hiramatsu if (tev->group) 15004235b045SMasami Hiramatsu free(tev->group); 15014235b045SMasami Hiramatsu if (tev->point.symbol) 15024235b045SMasami Hiramatsu free(tev->point.symbol); 1503190b57fcSMasami Hiramatsu if (tev->point.module) 1504190b57fcSMasami Hiramatsu free(tev->point.module); 15054235b045SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 15064235b045SMasami Hiramatsu if (tev->args[i].name) 15074235b045SMasami Hiramatsu free(tev->args[i].name); 15084235b045SMasami Hiramatsu if (tev->args[i].value) 15094235b045SMasami Hiramatsu free(tev->args[i].value); 15104984912eSMasami Hiramatsu if (tev->args[i].type) 15114984912eSMasami Hiramatsu free(tev->args[i].type); 15124235b045SMasami Hiramatsu ref = tev->args[i].ref; 15134235b045SMasami Hiramatsu while (ref) { 15144235b045SMasami Hiramatsu next = ref->next; 15154235b045SMasami Hiramatsu free(ref); 15164235b045SMasami Hiramatsu ref = next; 15174235b045SMasami Hiramatsu } 15184235b045SMasami Hiramatsu } 15194235b045SMasami Hiramatsu if (tev->args) 15204235b045SMasami Hiramatsu free(tev->args); 15214235b045SMasami Hiramatsu memset(tev, 0, sizeof(*tev)); 15224de189feSMasami Hiramatsu } 15234de189feSMasami Hiramatsu 1524225466f1SSrikar Dronamraju static void print_warn_msg(const char *file, bool is_kprobe) 1525225466f1SSrikar Dronamraju { 1526225466f1SSrikar Dronamraju 1527225466f1SSrikar Dronamraju if (errno == ENOENT) { 1528225466f1SSrikar Dronamraju const char *config; 1529225466f1SSrikar Dronamraju 1530225466f1SSrikar Dronamraju if (!is_kprobe) 1531225466f1SSrikar Dronamraju config = "CONFIG_UPROBE_EVENTS"; 1532225466f1SSrikar Dronamraju else 1533225466f1SSrikar Dronamraju config = "CONFIG_KPROBE_EVENTS"; 1534225466f1SSrikar Dronamraju 1535225466f1SSrikar Dronamraju pr_warning("%s file does not exist - please rebuild kernel" 1536225466f1SSrikar Dronamraju " with %s.\n", file, config); 1537225466f1SSrikar Dronamraju } else 1538225466f1SSrikar Dronamraju pr_warning("Failed to open %s file: %s\n", file, 1539225466f1SSrikar Dronamraju strerror(errno)); 1540225466f1SSrikar Dronamraju } 1541225466f1SSrikar Dronamraju 1542225466f1SSrikar Dronamraju static int open_probe_events(const char *trace_file, bool readwrite, 1543225466f1SSrikar Dronamraju bool is_kprobe) 15444de189feSMasami Hiramatsu { 15454de189feSMasami Hiramatsu char buf[PATH_MAX]; 15467ca5989dSMasami Hiramatsu const char *__debugfs; 15474de189feSMasami Hiramatsu int ret; 15484de189feSMasami Hiramatsu 15497ca5989dSMasami Hiramatsu __debugfs = debugfs_find_mountpoint(); 15507ca5989dSMasami Hiramatsu if (__debugfs == NULL) { 15517ca5989dSMasami Hiramatsu pr_warning("Debugfs is not mounted.\n"); 15527ca5989dSMasami Hiramatsu return -ENOENT; 15537ca5989dSMasami Hiramatsu } 15547ca5989dSMasami Hiramatsu 1555225466f1SSrikar Dronamraju ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file); 1556146a1439SMasami Hiramatsu if (ret >= 0) { 15577ca5989dSMasami Hiramatsu pr_debug("Opening %s write=%d\n", buf, readwrite); 1558f4d7da49SMasami Hiramatsu if (readwrite && !probe_event_dry_run) 1559f4d7da49SMasami Hiramatsu ret = open(buf, O_RDWR, O_APPEND); 1560f4d7da49SMasami Hiramatsu else 1561f4d7da49SMasami Hiramatsu ret = open(buf, O_RDONLY, 0); 1562f4d7da49SMasami Hiramatsu 1563225466f1SSrikar Dronamraju if (ret < 0) 1564225466f1SSrikar Dronamraju print_warn_msg(buf, is_kprobe); 15654de189feSMasami Hiramatsu } 15664de189feSMasami Hiramatsu return ret; 15674de189feSMasami Hiramatsu } 15684de189feSMasami Hiramatsu 1569225466f1SSrikar Dronamraju static int open_kprobe_events(bool readwrite) 1570225466f1SSrikar Dronamraju { 1571225466f1SSrikar Dronamraju return open_probe_events("tracing/kprobe_events", readwrite, true); 1572225466f1SSrikar Dronamraju } 1573225466f1SSrikar Dronamraju 1574225466f1SSrikar Dronamraju static int open_uprobe_events(bool readwrite) 1575225466f1SSrikar Dronamraju { 1576225466f1SSrikar Dronamraju return open_probe_events("tracing/uprobe_events", readwrite, false); 1577225466f1SSrikar Dronamraju } 1578225466f1SSrikar Dronamraju 1579225466f1SSrikar Dronamraju /* Get raw string list of current kprobe_events or uprobe_events */ 15800e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_command_rawlist(int fd) 15814de189feSMasami Hiramatsu { 15824de189feSMasami Hiramatsu int ret, idx; 15834de189feSMasami Hiramatsu FILE *fp; 15844de189feSMasami Hiramatsu char buf[MAX_CMDLEN]; 15854de189feSMasami Hiramatsu char *p; 15864de189feSMasami Hiramatsu struct strlist *sl; 15874de189feSMasami Hiramatsu 15884de189feSMasami Hiramatsu sl = strlist__new(true, NULL); 15894de189feSMasami Hiramatsu 15904de189feSMasami Hiramatsu fp = fdopen(dup(fd), "r"); 15914de189feSMasami Hiramatsu while (!feof(fp)) { 15924de189feSMasami Hiramatsu p = fgets(buf, MAX_CMDLEN, fp); 15934de189feSMasami Hiramatsu if (!p) 15944de189feSMasami Hiramatsu break; 15954de189feSMasami Hiramatsu 15964de189feSMasami Hiramatsu idx = strlen(p) - 1; 15974de189feSMasami Hiramatsu if (p[idx] == '\n') 15984de189feSMasami Hiramatsu p[idx] = '\0'; 15994de189feSMasami Hiramatsu ret = strlist__add(sl, buf); 1600146a1439SMasami Hiramatsu if (ret < 0) { 1601146a1439SMasami Hiramatsu pr_debug("strlist__add failed: %s\n", strerror(-ret)); 1602146a1439SMasami Hiramatsu strlist__delete(sl); 1603146a1439SMasami Hiramatsu return NULL; 1604146a1439SMasami Hiramatsu } 16054de189feSMasami Hiramatsu } 16064de189feSMasami Hiramatsu fclose(fp); 16074de189feSMasami Hiramatsu 16084de189feSMasami Hiramatsu return sl; 16094de189feSMasami Hiramatsu } 16104de189feSMasami Hiramatsu 1611278498d4SMasami Hiramatsu /* Show an event */ 1612146a1439SMasami Hiramatsu static int show_perf_probe_event(struct perf_probe_event *pev) 1613278498d4SMasami Hiramatsu { 16147e990a51SMasami Hiramatsu int i, ret; 1615278498d4SMasami Hiramatsu char buf[128]; 16164235b045SMasami Hiramatsu char *place; 1617278498d4SMasami Hiramatsu 16184235b045SMasami Hiramatsu /* Synthesize only event probe point */ 16194235b045SMasami Hiramatsu place = synthesize_perf_probe_point(&pev->point); 1620146a1439SMasami Hiramatsu if (!place) 1621146a1439SMasami Hiramatsu return -EINVAL; 16224235b045SMasami Hiramatsu 16234235b045SMasami Hiramatsu ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); 16247e990a51SMasami Hiramatsu if (ret < 0) 1625146a1439SMasami Hiramatsu return ret; 1626146a1439SMasami Hiramatsu 1627fb1587d8SMasami Hiramatsu printf(" %-20s (on %s", buf, place); 1628278498d4SMasami Hiramatsu 16294235b045SMasami Hiramatsu if (pev->nargs > 0) { 1630278498d4SMasami Hiramatsu printf(" with"); 16317df2f329SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) { 1632146a1439SMasami Hiramatsu ret = synthesize_perf_probe_arg(&pev->args[i], 1633146a1439SMasami Hiramatsu buf, 128); 1634146a1439SMasami Hiramatsu if (ret < 0) 1635146a1439SMasami Hiramatsu break; 16367df2f329SMasami Hiramatsu printf(" %s", buf); 16377df2f329SMasami Hiramatsu } 1638278498d4SMasami Hiramatsu } 1639278498d4SMasami Hiramatsu printf(")\n"); 16404235b045SMasami Hiramatsu free(place); 1641146a1439SMasami Hiramatsu return ret; 1642278498d4SMasami Hiramatsu } 1643278498d4SMasami Hiramatsu 1644225466f1SSrikar Dronamraju static int __show_perf_probe_events(int fd, bool is_kprobe) 16454de189feSMasami Hiramatsu { 1646225466f1SSrikar Dronamraju int ret = 0; 16470e60836bSSrikar Dronamraju struct probe_trace_event tev; 16484235b045SMasami Hiramatsu struct perf_probe_event pev; 16494de189feSMasami Hiramatsu struct strlist *rawlist; 16504de189feSMasami Hiramatsu struct str_node *ent; 16514de189feSMasami Hiramatsu 16524235b045SMasami Hiramatsu memset(&tev, 0, sizeof(tev)); 16534235b045SMasami Hiramatsu memset(&pev, 0, sizeof(pev)); 165472041334SMasami Hiramatsu 16550e60836bSSrikar Dronamraju rawlist = get_probe_trace_command_rawlist(fd); 1656146a1439SMasami Hiramatsu if (!rawlist) 1657146a1439SMasami Hiramatsu return -ENOENT; 16584de189feSMasami Hiramatsu 1659adf365f4SMasami Hiramatsu strlist__for_each(ent, rawlist) { 16600e60836bSSrikar Dronamraju ret = parse_probe_trace_command(ent->s, &tev); 1661146a1439SMasami Hiramatsu if (ret >= 0) { 1662225466f1SSrikar Dronamraju ret = convert_to_perf_probe_event(&tev, &pev, 1663225466f1SSrikar Dronamraju is_kprobe); 1664146a1439SMasami Hiramatsu if (ret >= 0) 1665146a1439SMasami Hiramatsu ret = show_perf_probe_event(&pev); 1666146a1439SMasami Hiramatsu } 16674235b045SMasami Hiramatsu clear_perf_probe_event(&pev); 16680e60836bSSrikar Dronamraju clear_probe_trace_event(&tev); 1669146a1439SMasami Hiramatsu if (ret < 0) 1670146a1439SMasami Hiramatsu break; 16714de189feSMasami Hiramatsu } 16724de189feSMasami Hiramatsu strlist__delete(rawlist); 1673146a1439SMasami Hiramatsu 1674146a1439SMasami Hiramatsu return ret; 16754de189feSMasami Hiramatsu } 16764de189feSMasami Hiramatsu 1677225466f1SSrikar Dronamraju /* List up current perf-probe events */ 1678225466f1SSrikar Dronamraju int show_perf_probe_events(void) 1679225466f1SSrikar Dronamraju { 1680225466f1SSrikar Dronamraju int fd, ret; 1681225466f1SSrikar Dronamraju 1682225466f1SSrikar Dronamraju setup_pager(); 1683225466f1SSrikar Dronamraju fd = open_kprobe_events(false); 1684225466f1SSrikar Dronamraju 1685225466f1SSrikar Dronamraju if (fd < 0) 1686225466f1SSrikar Dronamraju return fd; 1687225466f1SSrikar Dronamraju 1688225466f1SSrikar Dronamraju ret = init_vmlinux(); 1689225466f1SSrikar Dronamraju if (ret < 0) 1690225466f1SSrikar Dronamraju return ret; 1691225466f1SSrikar Dronamraju 1692225466f1SSrikar Dronamraju ret = __show_perf_probe_events(fd, true); 1693225466f1SSrikar Dronamraju close(fd); 1694225466f1SSrikar Dronamraju 1695225466f1SSrikar Dronamraju fd = open_uprobe_events(false); 1696225466f1SSrikar Dronamraju if (fd >= 0) { 1697225466f1SSrikar Dronamraju ret = __show_perf_probe_events(fd, false); 1698225466f1SSrikar Dronamraju close(fd); 1699225466f1SSrikar Dronamraju } 1700225466f1SSrikar Dronamraju 1701225466f1SSrikar Dronamraju return ret; 1702225466f1SSrikar Dronamraju } 1703225466f1SSrikar Dronamraju 1704b498ce1fSMasami Hiramatsu /* Get current perf-probe event names */ 17050e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_event_names(int fd, bool include_group) 1706b498ce1fSMasami Hiramatsu { 1707fa28244dSMasami Hiramatsu char buf[128]; 1708b498ce1fSMasami Hiramatsu struct strlist *sl, *rawlist; 1709b498ce1fSMasami Hiramatsu struct str_node *ent; 17100e60836bSSrikar Dronamraju struct probe_trace_event tev; 1711146a1439SMasami Hiramatsu int ret = 0; 1712b498ce1fSMasami Hiramatsu 17134235b045SMasami Hiramatsu memset(&tev, 0, sizeof(tev)); 17140e60836bSSrikar Dronamraju rawlist = get_probe_trace_command_rawlist(fd); 1715e1d2017bSMasami Hiramatsu sl = strlist__new(true, NULL); 1716adf365f4SMasami Hiramatsu strlist__for_each(ent, rawlist) { 17170e60836bSSrikar Dronamraju ret = parse_probe_trace_command(ent->s, &tev); 1718146a1439SMasami Hiramatsu if (ret < 0) 1719146a1439SMasami Hiramatsu break; 1720fa28244dSMasami Hiramatsu if (include_group) { 1721146a1439SMasami Hiramatsu ret = e_snprintf(buf, 128, "%s:%s", tev.group, 1722146a1439SMasami Hiramatsu tev.event); 1723146a1439SMasami Hiramatsu if (ret >= 0) 1724146a1439SMasami Hiramatsu ret = strlist__add(sl, buf); 1725fa28244dSMasami Hiramatsu } else 1726146a1439SMasami Hiramatsu ret = strlist__add(sl, tev.event); 17270e60836bSSrikar Dronamraju clear_probe_trace_event(&tev); 1728146a1439SMasami Hiramatsu if (ret < 0) 1729146a1439SMasami Hiramatsu break; 1730b498ce1fSMasami Hiramatsu } 1731b498ce1fSMasami Hiramatsu strlist__delete(rawlist); 1732b498ce1fSMasami Hiramatsu 1733146a1439SMasami Hiramatsu if (ret < 0) { 1734146a1439SMasami Hiramatsu strlist__delete(sl); 1735146a1439SMasami Hiramatsu return NULL; 1736146a1439SMasami Hiramatsu } 1737b498ce1fSMasami Hiramatsu return sl; 1738b498ce1fSMasami Hiramatsu } 1739b498ce1fSMasami Hiramatsu 17400e60836bSSrikar Dronamraju static int write_probe_trace_event(int fd, struct probe_trace_event *tev) 174150656eecSMasami Hiramatsu { 17426eca8cc3SFrederic Weisbecker int ret = 0; 17430e60836bSSrikar Dronamraju char *buf = synthesize_probe_trace_command(tev); 174450656eecSMasami Hiramatsu 1745146a1439SMasami Hiramatsu if (!buf) { 17460e60836bSSrikar Dronamraju pr_debug("Failed to synthesize probe trace event.\n"); 1747146a1439SMasami Hiramatsu return -EINVAL; 1748146a1439SMasami Hiramatsu } 1749146a1439SMasami Hiramatsu 1750fa28244dSMasami Hiramatsu pr_debug("Writing event: %s\n", buf); 1751f4d7da49SMasami Hiramatsu if (!probe_event_dry_run) { 175250656eecSMasami Hiramatsu ret = write(fd, buf, strlen(buf)); 175350656eecSMasami Hiramatsu if (ret <= 0) 1754146a1439SMasami Hiramatsu pr_warning("Failed to write event: %s\n", 1755146a1439SMasami Hiramatsu strerror(errno)); 175650656eecSMasami Hiramatsu } 17574235b045SMasami Hiramatsu free(buf); 1758146a1439SMasami Hiramatsu return ret; 1759f4d7da49SMasami Hiramatsu } 176050656eecSMasami Hiramatsu 1761146a1439SMasami Hiramatsu static int get_new_event_name(char *buf, size_t len, const char *base, 1762d761b08bSMasami Hiramatsu struct strlist *namelist, bool allow_suffix) 1763b498ce1fSMasami Hiramatsu { 1764b498ce1fSMasami Hiramatsu int i, ret; 176517f88fcdSMasami Hiramatsu 176617f88fcdSMasami Hiramatsu /* Try no suffix */ 176717f88fcdSMasami Hiramatsu ret = e_snprintf(buf, len, "%s", base); 1768146a1439SMasami Hiramatsu if (ret < 0) { 1769146a1439SMasami Hiramatsu pr_debug("snprintf() failed: %s\n", strerror(-ret)); 1770146a1439SMasami Hiramatsu return ret; 1771146a1439SMasami Hiramatsu } 177217f88fcdSMasami Hiramatsu if (!strlist__has_entry(namelist, buf)) 1773146a1439SMasami Hiramatsu return 0; 177417f88fcdSMasami Hiramatsu 1775d761b08bSMasami Hiramatsu if (!allow_suffix) { 1776d761b08bSMasami Hiramatsu pr_warning("Error: event \"%s\" already exists. " 1777d761b08bSMasami Hiramatsu "(Use -f to force duplicates.)\n", base); 1778146a1439SMasami Hiramatsu return -EEXIST; 1779d761b08bSMasami Hiramatsu } 1780d761b08bSMasami Hiramatsu 178117f88fcdSMasami Hiramatsu /* Try to add suffix */ 178217f88fcdSMasami Hiramatsu for (i = 1; i < MAX_EVENT_INDEX; i++) { 1783b498ce1fSMasami Hiramatsu ret = e_snprintf(buf, len, "%s_%d", base, i); 1784146a1439SMasami Hiramatsu if (ret < 0) { 1785146a1439SMasami Hiramatsu pr_debug("snprintf() failed: %s\n", strerror(-ret)); 1786146a1439SMasami Hiramatsu return ret; 1787146a1439SMasami Hiramatsu } 1788b498ce1fSMasami Hiramatsu if (!strlist__has_entry(namelist, buf)) 1789b498ce1fSMasami Hiramatsu break; 1790b498ce1fSMasami Hiramatsu } 1791146a1439SMasami Hiramatsu if (i == MAX_EVENT_INDEX) { 1792146a1439SMasami Hiramatsu pr_warning("Too many events are on the same function.\n"); 1793146a1439SMasami Hiramatsu ret = -ERANGE; 1794b498ce1fSMasami Hiramatsu } 1795b498ce1fSMasami Hiramatsu 1796146a1439SMasami Hiramatsu return ret; 1797146a1439SMasami Hiramatsu } 1798146a1439SMasami Hiramatsu 17990e60836bSSrikar Dronamraju static int __add_probe_trace_events(struct perf_probe_event *pev, 18000e60836bSSrikar Dronamraju struct probe_trace_event *tevs, 18014235b045SMasami Hiramatsu int ntevs, bool allow_suffix) 180250656eecSMasami Hiramatsu { 1803146a1439SMasami Hiramatsu int i, fd, ret; 18040e60836bSSrikar Dronamraju struct probe_trace_event *tev = NULL; 18054235b045SMasami Hiramatsu char buf[64]; 18064235b045SMasami Hiramatsu const char *event, *group; 1807b498ce1fSMasami Hiramatsu struct strlist *namelist; 180850656eecSMasami Hiramatsu 1809225466f1SSrikar Dronamraju if (pev->uprobes) 1810225466f1SSrikar Dronamraju fd = open_uprobe_events(true); 1811225466f1SSrikar Dronamraju else 1812f4d7da49SMasami Hiramatsu fd = open_kprobe_events(true); 1813225466f1SSrikar Dronamraju 1814146a1439SMasami Hiramatsu if (fd < 0) 1815146a1439SMasami Hiramatsu return fd; 1816b498ce1fSMasami Hiramatsu /* Get current event names */ 18170e60836bSSrikar Dronamraju namelist = get_probe_trace_event_names(fd, false); 1818146a1439SMasami Hiramatsu if (!namelist) { 1819146a1439SMasami Hiramatsu pr_debug("Failed to get current event list.\n"); 1820146a1439SMasami Hiramatsu return -EIO; 1821146a1439SMasami Hiramatsu } 182250656eecSMasami Hiramatsu 1823146a1439SMasami Hiramatsu ret = 0; 1824a844d1efSSrikar Dronamraju printf("Added new event%s\n", (ntevs > 1) ? "s:" : ":"); 182502b95dadSMasami Hiramatsu for (i = 0; i < ntevs; i++) { 18264235b045SMasami Hiramatsu tev = &tevs[i]; 18274235b045SMasami Hiramatsu if (pev->event) 18284235b045SMasami Hiramatsu event = pev->event; 18294235b045SMasami Hiramatsu else 18304235b045SMasami Hiramatsu if (pev->point.function) 18314235b045SMasami Hiramatsu event = pev->point.function; 18324235b045SMasami Hiramatsu else 18334235b045SMasami Hiramatsu event = tev->point.symbol; 18344235b045SMasami Hiramatsu if (pev->group) 18354235b045SMasami Hiramatsu group = pev->group; 18364235b045SMasami Hiramatsu else 18374235b045SMasami Hiramatsu group = PERFPROBE_GROUP; 18384235b045SMasami Hiramatsu 1839b498ce1fSMasami Hiramatsu /* Get an unused new event name */ 1840146a1439SMasami Hiramatsu ret = get_new_event_name(buf, 64, event, 1841146a1439SMasami Hiramatsu namelist, allow_suffix); 1842146a1439SMasami Hiramatsu if (ret < 0) 1843146a1439SMasami Hiramatsu break; 18444235b045SMasami Hiramatsu event = buf; 18454235b045SMasami Hiramatsu 184602b95dadSMasami Hiramatsu tev->event = strdup(event); 184702b95dadSMasami Hiramatsu tev->group = strdup(group); 184802b95dadSMasami Hiramatsu if (tev->event == NULL || tev->group == NULL) { 184902b95dadSMasami Hiramatsu ret = -ENOMEM; 185002b95dadSMasami Hiramatsu break; 185102b95dadSMasami Hiramatsu } 18520e60836bSSrikar Dronamraju ret = write_probe_trace_event(fd, tev); 1853146a1439SMasami Hiramatsu if (ret < 0) 1854146a1439SMasami Hiramatsu break; 1855b498ce1fSMasami Hiramatsu /* Add added event name to namelist */ 1856b498ce1fSMasami Hiramatsu strlist__add(namelist, event); 18574235b045SMasami Hiramatsu 18584235b045SMasami Hiramatsu /* Trick here - save current event/group */ 18594235b045SMasami Hiramatsu event = pev->event; 18604235b045SMasami Hiramatsu group = pev->group; 18614235b045SMasami Hiramatsu pev->event = tev->event; 18624235b045SMasami Hiramatsu pev->group = tev->group; 18634235b045SMasami Hiramatsu show_perf_probe_event(pev); 18644235b045SMasami Hiramatsu /* Trick here - restore current event/group */ 18654235b045SMasami Hiramatsu pev->event = (char *)event; 18664235b045SMasami Hiramatsu pev->group = (char *)group; 18674235b045SMasami Hiramatsu 1868d761b08bSMasami Hiramatsu /* 1869d761b08bSMasami Hiramatsu * Probes after the first probe which comes from same 1870d761b08bSMasami Hiramatsu * user input are always allowed to add suffix, because 1871d761b08bSMasami Hiramatsu * there might be several addresses corresponding to 1872d761b08bSMasami Hiramatsu * one code line. 1873d761b08bSMasami Hiramatsu */ 1874d761b08bSMasami Hiramatsu allow_suffix = true; 187550656eecSMasami Hiramatsu } 1876146a1439SMasami Hiramatsu 1877146a1439SMasami Hiramatsu if (ret >= 0) { 1878a9b495b0SMasami Hiramatsu /* Show how to use the event. */ 1879a844d1efSSrikar Dronamraju printf("\nYou can now use it in all perf tools, such as:\n\n"); 1880146a1439SMasami Hiramatsu printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, 1881146a1439SMasami Hiramatsu tev->event); 1882146a1439SMasami Hiramatsu } 1883a9b495b0SMasami Hiramatsu 1884e1d2017bSMasami Hiramatsu strlist__delete(namelist); 188550656eecSMasami Hiramatsu close(fd); 1886146a1439SMasami Hiramatsu return ret; 188750656eecSMasami Hiramatsu } 1888fa28244dSMasami Hiramatsu 18890e60836bSSrikar Dronamraju static int convert_to_probe_trace_events(struct perf_probe_event *pev, 18900e60836bSSrikar Dronamraju struct probe_trace_event **tevs, 18914eced234SSrikar Dronamraju int max_tevs, const char *target) 1892e0faa8d3SMasami Hiramatsu { 1893e0faa8d3SMasami Hiramatsu struct symbol *sym; 1894e334016fSMasami Hiramatsu int ret = 0, i; 18950e60836bSSrikar Dronamraju struct probe_trace_event *tev; 18964235b045SMasami Hiramatsu 18974b4da7f7SMasami Hiramatsu /* Convert perf_probe_event with debuginfo */ 18984eced234SSrikar Dronamraju ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); 1899e334016fSMasami Hiramatsu if (ret != 0) 1900190b57fcSMasami Hiramatsu return ret; /* Found in debuginfo or got an error */ 1901e0faa8d3SMasami Hiramatsu 19024235b045SMasami Hiramatsu /* Allocate trace event buffer */ 19030e60836bSSrikar Dronamraju tev = *tevs = zalloc(sizeof(struct probe_trace_event)); 1904e334016fSMasami Hiramatsu if (tev == NULL) 1905e334016fSMasami Hiramatsu return -ENOMEM; 1906e0faa8d3SMasami Hiramatsu 19074235b045SMasami Hiramatsu /* Copy parameters */ 190802b95dadSMasami Hiramatsu tev->point.symbol = strdup(pev->point.function); 190902b95dadSMasami Hiramatsu if (tev->point.symbol == NULL) { 191002b95dadSMasami Hiramatsu ret = -ENOMEM; 191102b95dadSMasami Hiramatsu goto error; 191202b95dadSMasami Hiramatsu } 1913ce27a443SJovi Zhang 19144eced234SSrikar Dronamraju if (target) { 19154eced234SSrikar Dronamraju tev->point.module = strdup(target); 1916190b57fcSMasami Hiramatsu if (tev->point.module == NULL) { 1917190b57fcSMasami Hiramatsu ret = -ENOMEM; 1918190b57fcSMasami Hiramatsu goto error; 1919190b57fcSMasami Hiramatsu } 1920ce27a443SJovi Zhang } 1921ce27a443SJovi Zhang 19224235b045SMasami Hiramatsu tev->point.offset = pev->point.offset; 192304ddd04bSMasami Hiramatsu tev->point.retprobe = pev->point.retprobe; 19244235b045SMasami Hiramatsu tev->nargs = pev->nargs; 1925225466f1SSrikar Dronamraju tev->uprobes = pev->uprobes; 1926225466f1SSrikar Dronamraju 19274235b045SMasami Hiramatsu if (tev->nargs) { 19280e60836bSSrikar Dronamraju tev->args = zalloc(sizeof(struct probe_trace_arg) 19294235b045SMasami Hiramatsu * tev->nargs); 1930e334016fSMasami Hiramatsu if (tev->args == NULL) { 193102b95dadSMasami Hiramatsu ret = -ENOMEM; 193202b95dadSMasami Hiramatsu goto error; 1933e334016fSMasami Hiramatsu } 193448481938SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 193502b95dadSMasami Hiramatsu if (pev->args[i].name) { 193602b95dadSMasami Hiramatsu tev->args[i].name = strdup(pev->args[i].name); 193702b95dadSMasami Hiramatsu if (tev->args[i].name == NULL) { 193802b95dadSMasami Hiramatsu ret = -ENOMEM; 193902b95dadSMasami Hiramatsu goto error; 194002b95dadSMasami Hiramatsu } 194102b95dadSMasami Hiramatsu } 194202b95dadSMasami Hiramatsu tev->args[i].value = strdup(pev->args[i].var); 194302b95dadSMasami Hiramatsu if (tev->args[i].value == NULL) { 194402b95dadSMasami Hiramatsu ret = -ENOMEM; 194502b95dadSMasami Hiramatsu goto error; 194602b95dadSMasami Hiramatsu } 194702b95dadSMasami Hiramatsu if (pev->args[i].type) { 194802b95dadSMasami Hiramatsu tev->args[i].type = strdup(pev->args[i].type); 194902b95dadSMasami Hiramatsu if (tev->args[i].type == NULL) { 195002b95dadSMasami Hiramatsu ret = -ENOMEM; 195102b95dadSMasami Hiramatsu goto error; 195202b95dadSMasami Hiramatsu } 195302b95dadSMasami Hiramatsu } 195448481938SMasami Hiramatsu } 1955e0faa8d3SMasami Hiramatsu } 1956e0faa8d3SMasami Hiramatsu 1957225466f1SSrikar Dronamraju if (pev->uprobes) 1958225466f1SSrikar Dronamraju return 1; 1959225466f1SSrikar Dronamraju 19604235b045SMasami Hiramatsu /* Currently just checking function name from symbol map */ 1961469b9b88SMasami Hiramatsu sym = __find_kernel_function_by_name(tev->point.symbol, NULL); 1962146a1439SMasami Hiramatsu if (!sym) { 1963146a1439SMasami Hiramatsu pr_warning("Kernel symbol \'%s\' not found.\n", 19644235b045SMasami Hiramatsu tev->point.symbol); 196502b95dadSMasami Hiramatsu ret = -ENOENT; 196602b95dadSMasami Hiramatsu goto error; 19671c1bc922SPrashanth Nageshappa } else if (tev->point.offset > sym->end - sym->start) { 19681c1bc922SPrashanth Nageshappa pr_warning("Offset specified is greater than size of %s\n", 19691c1bc922SPrashanth Nageshappa tev->point.symbol); 19701c1bc922SPrashanth Nageshappa ret = -ENOENT; 19711c1bc922SPrashanth Nageshappa goto error; 19721c1bc922SPrashanth Nageshappa 197302b95dadSMasami Hiramatsu } 197402b95dadSMasami Hiramatsu 197502b95dadSMasami Hiramatsu return 1; 197602b95dadSMasami Hiramatsu error: 19770e60836bSSrikar Dronamraju clear_probe_trace_event(tev); 1978e334016fSMasami Hiramatsu free(tev); 1979e334016fSMasami Hiramatsu *tevs = NULL; 1980e334016fSMasami Hiramatsu return ret; 19814235b045SMasami Hiramatsu } 19824235b045SMasami Hiramatsu 19834235b045SMasami Hiramatsu struct __event_package { 19844235b045SMasami Hiramatsu struct perf_probe_event *pev; 19850e60836bSSrikar Dronamraju struct probe_trace_event *tevs; 19864235b045SMasami Hiramatsu int ntevs; 19874235b045SMasami Hiramatsu }; 19884235b045SMasami Hiramatsu 1989146a1439SMasami Hiramatsu int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 19904eced234SSrikar Dronamraju int max_tevs, const char *target, bool force_add) 19914235b045SMasami Hiramatsu { 1992146a1439SMasami Hiramatsu int i, j, ret; 19934235b045SMasami Hiramatsu struct __event_package *pkgs; 19944235b045SMasami Hiramatsu 1995225466f1SSrikar Dronamraju ret = 0; 1996e334016fSMasami Hiramatsu pkgs = zalloc(sizeof(struct __event_package) * npevs); 1997225466f1SSrikar Dronamraju 1998e334016fSMasami Hiramatsu if (pkgs == NULL) 1999e334016fSMasami Hiramatsu return -ENOMEM; 20004235b045SMasami Hiramatsu 2001225466f1SSrikar Dronamraju if (!pevs->uprobes) 20024235b045SMasami Hiramatsu /* Init vmlinux path */ 2003146a1439SMasami Hiramatsu ret = init_vmlinux(); 2004225466f1SSrikar Dronamraju else 2005225466f1SSrikar Dronamraju ret = init_user_exec(); 2006225466f1SSrikar Dronamraju 2007449e5b24SMasami Hiramatsu if (ret < 0) { 2008449e5b24SMasami Hiramatsu free(pkgs); 2009146a1439SMasami Hiramatsu return ret; 2010449e5b24SMasami Hiramatsu } 20114235b045SMasami Hiramatsu 20124235b045SMasami Hiramatsu /* Loop 1: convert all events */ 20134235b045SMasami Hiramatsu for (i = 0; i < npevs; i++) { 20144235b045SMasami Hiramatsu pkgs[i].pev = &pevs[i]; 20154235b045SMasami Hiramatsu /* Convert with or without debuginfo */ 20160e60836bSSrikar Dronamraju ret = convert_to_probe_trace_events(pkgs[i].pev, 2017469b9b88SMasami Hiramatsu &pkgs[i].tevs, 2018469b9b88SMasami Hiramatsu max_tevs, 20194eced234SSrikar Dronamraju target); 2020146a1439SMasami Hiramatsu if (ret < 0) 2021146a1439SMasami Hiramatsu goto end; 2022146a1439SMasami Hiramatsu pkgs[i].ntevs = ret; 20234235b045SMasami Hiramatsu } 20244235b045SMasami Hiramatsu 20254235b045SMasami Hiramatsu /* Loop 2: add all events */ 20268635bf6eSArnaldo Carvalho de Melo for (i = 0; i < npevs; i++) { 20270e60836bSSrikar Dronamraju ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, 20284235b045SMasami Hiramatsu pkgs[i].ntevs, force_add); 2029fbee632dSArnaldo Carvalho de Melo if (ret < 0) 2030fbee632dSArnaldo Carvalho de Melo break; 2031fbee632dSArnaldo Carvalho de Melo } 2032146a1439SMasami Hiramatsu end: 2033449e5b24SMasami Hiramatsu /* Loop 3: cleanup and free trace events */ 2034449e5b24SMasami Hiramatsu for (i = 0; i < npevs; i++) { 2035146a1439SMasami Hiramatsu for (j = 0; j < pkgs[i].ntevs; j++) 20360e60836bSSrikar Dronamraju clear_probe_trace_event(&pkgs[i].tevs[j]); 2037449e5b24SMasami Hiramatsu free(pkgs[i].tevs); 2038449e5b24SMasami Hiramatsu } 2039449e5b24SMasami Hiramatsu free(pkgs); 2040146a1439SMasami Hiramatsu 2041146a1439SMasami Hiramatsu return ret; 2042e0faa8d3SMasami Hiramatsu } 2043e0faa8d3SMasami Hiramatsu 20440e60836bSSrikar Dronamraju static int __del_trace_probe_event(int fd, struct str_node *ent) 2045bbbb521bSMasami Hiramatsu { 2046bbbb521bSMasami Hiramatsu char *p; 2047bbbb521bSMasami Hiramatsu char buf[128]; 20484235b045SMasami Hiramatsu int ret; 2049bbbb521bSMasami Hiramatsu 20500e60836bSSrikar Dronamraju /* Convert from perf-probe event to trace-probe event */ 2051146a1439SMasami Hiramatsu ret = e_snprintf(buf, 128, "-:%s", ent->s); 2052146a1439SMasami Hiramatsu if (ret < 0) 2053146a1439SMasami Hiramatsu goto error; 2054146a1439SMasami Hiramatsu 2055bbbb521bSMasami Hiramatsu p = strchr(buf + 2, ':'); 2056146a1439SMasami Hiramatsu if (!p) { 2057146a1439SMasami Hiramatsu pr_debug("Internal error: %s should have ':' but not.\n", 2058146a1439SMasami Hiramatsu ent->s); 2059146a1439SMasami Hiramatsu ret = -ENOTSUP; 2060146a1439SMasami Hiramatsu goto error; 2061146a1439SMasami Hiramatsu } 2062bbbb521bSMasami Hiramatsu *p = '/'; 2063bbbb521bSMasami Hiramatsu 20644235b045SMasami Hiramatsu pr_debug("Writing event: %s\n", buf); 20654235b045SMasami Hiramatsu ret = write(fd, buf, strlen(buf)); 206644a56040SMasami Hiramatsu if (ret < 0) { 206744a56040SMasami Hiramatsu ret = -errno; 2068146a1439SMasami Hiramatsu goto error; 206944a56040SMasami Hiramatsu } 2070146a1439SMasami Hiramatsu 2071a844d1efSSrikar Dronamraju printf("Removed event: %s\n", ent->s); 2072146a1439SMasami Hiramatsu return 0; 2073146a1439SMasami Hiramatsu error: 2074146a1439SMasami Hiramatsu pr_warning("Failed to delete event: %s\n", strerror(-ret)); 2075146a1439SMasami Hiramatsu return ret; 2076bbbb521bSMasami Hiramatsu } 2077bbbb521bSMasami Hiramatsu 2078225466f1SSrikar Dronamraju static int del_trace_probe_event(int fd, const char *buf, 2079225466f1SSrikar Dronamraju struct strlist *namelist) 2080fa28244dSMasami Hiramatsu { 2081bbbb521bSMasami Hiramatsu struct str_node *ent, *n; 2082225466f1SSrikar Dronamraju int ret = -1; 2083fa28244dSMasami Hiramatsu 2084bbbb521bSMasami Hiramatsu if (strpbrk(buf, "*?")) { /* Glob-exp */ 2085bbbb521bSMasami Hiramatsu strlist__for_each_safe(ent, n, namelist) 2086bbbb521bSMasami Hiramatsu if (strglobmatch(ent->s, buf)) { 20870e60836bSSrikar Dronamraju ret = __del_trace_probe_event(fd, ent); 2088146a1439SMasami Hiramatsu if (ret < 0) 2089146a1439SMasami Hiramatsu break; 20903e340590SMasami Hiramatsu strlist__remove(namelist, ent); 2091fa28244dSMasami Hiramatsu } 2092bbbb521bSMasami Hiramatsu } else { 2093bbbb521bSMasami Hiramatsu ent = strlist__find(namelist, buf); 2094bbbb521bSMasami Hiramatsu if (ent) { 20950e60836bSSrikar Dronamraju ret = __del_trace_probe_event(fd, ent); 2096146a1439SMasami Hiramatsu if (ret >= 0) 2097bbbb521bSMasami Hiramatsu strlist__remove(namelist, ent); 2098bbbb521bSMasami Hiramatsu } 2099bbbb521bSMasami Hiramatsu } 2100146a1439SMasami Hiramatsu 2101146a1439SMasami Hiramatsu return ret; 2102bbbb521bSMasami Hiramatsu } 2103fa28244dSMasami Hiramatsu 2104146a1439SMasami Hiramatsu int del_perf_probe_events(struct strlist *dellist) 2105fa28244dSMasami Hiramatsu { 2106225466f1SSrikar Dronamraju int ret = -1, ufd = -1, kfd = -1; 2107225466f1SSrikar Dronamraju char buf[128]; 2108fa28244dSMasami Hiramatsu const char *group, *event; 2109fa28244dSMasami Hiramatsu char *p, *str; 2110fa28244dSMasami Hiramatsu struct str_node *ent; 2111225466f1SSrikar Dronamraju struct strlist *namelist = NULL, *unamelist = NULL; 2112146a1439SMasami Hiramatsu 2113fa28244dSMasami Hiramatsu /* Get current event names */ 2114225466f1SSrikar Dronamraju kfd = open_kprobe_events(true); 2115225466f1SSrikar Dronamraju if (kfd < 0) 2116225466f1SSrikar Dronamraju return kfd; 2117225466f1SSrikar Dronamraju 2118225466f1SSrikar Dronamraju namelist = get_probe_trace_event_names(kfd, true); 2119225466f1SSrikar Dronamraju ufd = open_uprobe_events(true); 2120225466f1SSrikar Dronamraju 2121225466f1SSrikar Dronamraju if (ufd >= 0) 2122225466f1SSrikar Dronamraju unamelist = get_probe_trace_event_names(ufd, true); 2123225466f1SSrikar Dronamraju 2124225466f1SSrikar Dronamraju if (namelist == NULL && unamelist == NULL) 2125225466f1SSrikar Dronamraju goto error; 2126fa28244dSMasami Hiramatsu 2127adf365f4SMasami Hiramatsu strlist__for_each(ent, dellist) { 212802b95dadSMasami Hiramatsu str = strdup(ent->s); 212902b95dadSMasami Hiramatsu if (str == NULL) { 213002b95dadSMasami Hiramatsu ret = -ENOMEM; 2131225466f1SSrikar Dronamraju goto error; 213202b95dadSMasami Hiramatsu } 2133bbbb521bSMasami Hiramatsu pr_debug("Parsing: %s\n", str); 2134fa28244dSMasami Hiramatsu p = strchr(str, ':'); 2135fa28244dSMasami Hiramatsu if (p) { 2136fa28244dSMasami Hiramatsu group = str; 2137fa28244dSMasami Hiramatsu *p = '\0'; 2138fa28244dSMasami Hiramatsu event = p + 1; 2139fa28244dSMasami Hiramatsu } else { 2140bbbb521bSMasami Hiramatsu group = "*"; 2141fa28244dSMasami Hiramatsu event = str; 2142fa28244dSMasami Hiramatsu } 2143225466f1SSrikar Dronamraju 2144225466f1SSrikar Dronamraju ret = e_snprintf(buf, 128, "%s:%s", group, event); 2145225466f1SSrikar Dronamraju if (ret < 0) { 2146225466f1SSrikar Dronamraju pr_err("Failed to copy event."); 2147fa28244dSMasami Hiramatsu free(str); 2148225466f1SSrikar Dronamraju goto error; 2149fa28244dSMasami Hiramatsu } 2150225466f1SSrikar Dronamraju 2151225466f1SSrikar Dronamraju pr_debug("Group: %s, Event: %s\n", group, event); 2152225466f1SSrikar Dronamraju 2153225466f1SSrikar Dronamraju if (namelist) 2154225466f1SSrikar Dronamraju ret = del_trace_probe_event(kfd, buf, namelist); 2155225466f1SSrikar Dronamraju 2156225466f1SSrikar Dronamraju if (unamelist && ret != 0) 2157225466f1SSrikar Dronamraju ret = del_trace_probe_event(ufd, buf, unamelist); 2158225466f1SSrikar Dronamraju 2159225466f1SSrikar Dronamraju if (ret != 0) 2160225466f1SSrikar Dronamraju pr_info("Info: Event \"%s\" does not exist.\n", buf); 2161225466f1SSrikar Dronamraju 2162225466f1SSrikar Dronamraju free(str); 2163225466f1SSrikar Dronamraju } 2164225466f1SSrikar Dronamraju 2165225466f1SSrikar Dronamraju error: 2166225466f1SSrikar Dronamraju if (kfd >= 0) { 2167fa28244dSMasami Hiramatsu strlist__delete(namelist); 2168225466f1SSrikar Dronamraju close(kfd); 2169225466f1SSrikar Dronamraju } 2170225466f1SSrikar Dronamraju 2171225466f1SSrikar Dronamraju if (ufd >= 0) { 2172225466f1SSrikar Dronamraju strlist__delete(unamelist); 2173225466f1SSrikar Dronamraju close(ufd); 2174225466f1SSrikar Dronamraju } 2175146a1439SMasami Hiramatsu 2176146a1439SMasami Hiramatsu return ret; 2177fa28244dSMasami Hiramatsu } 2178225466f1SSrikar Dronamraju 21793c42258cSMasami Hiramatsu /* TODO: don't use a global variable for filter ... */ 21803c42258cSMasami Hiramatsu static struct strfilter *available_func_filter; 2181fa28244dSMasami Hiramatsu 2182e80711caSMasami Hiramatsu /* 21833c42258cSMasami Hiramatsu * If a symbol corresponds to a function with global binding and 21843c42258cSMasami Hiramatsu * matches filter return 0. For all others return 1. 2185e80711caSMasami Hiramatsu */ 21863c42258cSMasami Hiramatsu static int filter_available_functions(struct map *map __unused, 2187e80711caSMasami Hiramatsu struct symbol *sym) 2188e80711caSMasami Hiramatsu { 21893c42258cSMasami Hiramatsu if (sym->binding == STB_GLOBAL && 21903c42258cSMasami Hiramatsu strfilter__compare(available_func_filter, sym->name)) 2191e80711caSMasami Hiramatsu return 0; 21923c42258cSMasami Hiramatsu return 1; 2193e80711caSMasami Hiramatsu } 2194e80711caSMasami Hiramatsu 2195225466f1SSrikar Dronamraju static int __show_available_funcs(struct map *map) 2196e80711caSMasami Hiramatsu { 21973c42258cSMasami Hiramatsu if (map__load(map, filter_available_functions)) { 2198e80711caSMasami Hiramatsu pr_err("Failed to load map.\n"); 2199e80711caSMasami Hiramatsu return -EINVAL; 2200e80711caSMasami Hiramatsu } 2201e80711caSMasami Hiramatsu if (!dso__sorted_by_name(map->dso, map->type)) 2202e80711caSMasami Hiramatsu dso__sort_by_name(map->dso, map->type); 2203e80711caSMasami Hiramatsu 2204e80711caSMasami Hiramatsu dso__fprintf_symbols_by_name(map->dso, map->type, stdout); 2205e80711caSMasami Hiramatsu return 0; 2206e80711caSMasami Hiramatsu } 2207225466f1SSrikar Dronamraju 2208225466f1SSrikar Dronamraju static int available_kernel_funcs(const char *module) 2209225466f1SSrikar Dronamraju { 2210225466f1SSrikar Dronamraju struct map *map; 2211225466f1SSrikar Dronamraju int ret; 2212225466f1SSrikar Dronamraju 2213225466f1SSrikar Dronamraju ret = init_vmlinux(); 2214225466f1SSrikar Dronamraju if (ret < 0) 2215225466f1SSrikar Dronamraju return ret; 2216225466f1SSrikar Dronamraju 2217225466f1SSrikar Dronamraju map = kernel_get_module_map(module); 2218225466f1SSrikar Dronamraju if (!map) { 2219225466f1SSrikar Dronamraju pr_err("Failed to find %s map.\n", (module) ? : "kernel"); 2220225466f1SSrikar Dronamraju return -EINVAL; 2221225466f1SSrikar Dronamraju } 2222225466f1SSrikar Dronamraju return __show_available_funcs(map); 2223225466f1SSrikar Dronamraju } 2224225466f1SSrikar Dronamraju 2225225466f1SSrikar Dronamraju static int available_user_funcs(const char *target) 2226225466f1SSrikar Dronamraju { 2227225466f1SSrikar Dronamraju struct map *map; 2228225466f1SSrikar Dronamraju int ret; 2229225466f1SSrikar Dronamraju 2230225466f1SSrikar Dronamraju ret = init_user_exec(); 2231225466f1SSrikar Dronamraju if (ret < 0) 2232225466f1SSrikar Dronamraju return ret; 2233225466f1SSrikar Dronamraju 2234225466f1SSrikar Dronamraju map = dso__new_map(target); 2235225466f1SSrikar Dronamraju ret = __show_available_funcs(map); 2236225466f1SSrikar Dronamraju dso__delete(map->dso); 2237225466f1SSrikar Dronamraju map__delete(map); 2238225466f1SSrikar Dronamraju return ret; 2239225466f1SSrikar Dronamraju } 2240225466f1SSrikar Dronamraju 2241225466f1SSrikar Dronamraju int show_available_funcs(const char *target, struct strfilter *_filter, 2242225466f1SSrikar Dronamraju bool user) 2243225466f1SSrikar Dronamraju { 2244225466f1SSrikar Dronamraju setup_pager(); 2245225466f1SSrikar Dronamraju available_func_filter = _filter; 2246225466f1SSrikar Dronamraju 2247225466f1SSrikar Dronamraju if (!user) 2248225466f1SSrikar Dronamraju return available_kernel_funcs(target); 2249225466f1SSrikar Dronamraju 2250225466f1SSrikar Dronamraju return available_user_funcs(target); 2251225466f1SSrikar Dronamraju } 2252225466f1SSrikar Dronamraju 2253225466f1SSrikar Dronamraju /* 2254225466f1SSrikar Dronamraju * uprobe_events only accepts address: 2255225466f1SSrikar Dronamraju * Convert function and any offset to address 2256225466f1SSrikar Dronamraju */ 2257225466f1SSrikar Dronamraju static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec) 2258225466f1SSrikar Dronamraju { 2259225466f1SSrikar Dronamraju struct perf_probe_point *pp = &pev->point; 2260225466f1SSrikar Dronamraju struct symbol *sym; 2261225466f1SSrikar Dronamraju struct map *map = NULL; 2262225466f1SSrikar Dronamraju char *function = NULL, *name = NULL; 2263225466f1SSrikar Dronamraju int ret = -EINVAL; 2264225466f1SSrikar Dronamraju unsigned long long vaddr = 0; 2265225466f1SSrikar Dronamraju 2266225466f1SSrikar Dronamraju if (!pp->function) { 2267225466f1SSrikar Dronamraju pr_warning("No function specified for uprobes"); 2268225466f1SSrikar Dronamraju goto out; 2269225466f1SSrikar Dronamraju } 2270225466f1SSrikar Dronamraju 2271225466f1SSrikar Dronamraju function = strdup(pp->function); 2272225466f1SSrikar Dronamraju if (!function) { 2273225466f1SSrikar Dronamraju pr_warning("Failed to allocate memory by strdup.\n"); 2274225466f1SSrikar Dronamraju ret = -ENOMEM; 2275225466f1SSrikar Dronamraju goto out; 2276225466f1SSrikar Dronamraju } 2277225466f1SSrikar Dronamraju 2278225466f1SSrikar Dronamraju name = realpath(exec, NULL); 2279225466f1SSrikar Dronamraju if (!name) { 2280225466f1SSrikar Dronamraju pr_warning("Cannot find realpath for %s.\n", exec); 2281225466f1SSrikar Dronamraju goto out; 2282225466f1SSrikar Dronamraju } 2283225466f1SSrikar Dronamraju map = dso__new_map(name); 2284225466f1SSrikar Dronamraju if (!map) { 2285225466f1SSrikar Dronamraju pr_warning("Cannot find appropriate DSO for %s.\n", exec); 2286225466f1SSrikar Dronamraju goto out; 2287225466f1SSrikar Dronamraju } 2288225466f1SSrikar Dronamraju available_func_filter = strfilter__new(function, NULL); 2289225466f1SSrikar Dronamraju if (map__load(map, filter_available_functions)) { 2290225466f1SSrikar Dronamraju pr_err("Failed to load map.\n"); 2291225466f1SSrikar Dronamraju goto out; 2292225466f1SSrikar Dronamraju } 2293225466f1SSrikar Dronamraju 2294225466f1SSrikar Dronamraju sym = map__find_symbol_by_name(map, function, NULL); 2295225466f1SSrikar Dronamraju if (!sym) { 2296225466f1SSrikar Dronamraju pr_warning("Cannot find %s in DSO %s\n", function, exec); 2297225466f1SSrikar Dronamraju goto out; 2298225466f1SSrikar Dronamraju } 2299225466f1SSrikar Dronamraju 2300225466f1SSrikar Dronamraju if (map->start > sym->start) 2301225466f1SSrikar Dronamraju vaddr = map->start; 2302225466f1SSrikar Dronamraju vaddr += sym->start + pp->offset + map->pgoff; 2303225466f1SSrikar Dronamraju pp->offset = 0; 2304225466f1SSrikar Dronamraju 2305225466f1SSrikar Dronamraju if (!pev->event) { 2306225466f1SSrikar Dronamraju pev->event = function; 2307225466f1SSrikar Dronamraju function = NULL; 2308225466f1SSrikar Dronamraju } 2309225466f1SSrikar Dronamraju if (!pev->group) { 2310*1fb89448SDavid Ahern char *ptr1, *ptr2, *exec_copy; 2311225466f1SSrikar Dronamraju 2312225466f1SSrikar Dronamraju pev->group = zalloc(sizeof(char *) * 64); 2313*1fb89448SDavid Ahern exec_copy = strdup(exec); 2314*1fb89448SDavid Ahern if (!exec_copy) { 2315*1fb89448SDavid Ahern ret = -ENOMEM; 2316*1fb89448SDavid Ahern pr_warning("Failed to copy exec string.\n"); 2317*1fb89448SDavid Ahern goto out; 2318*1fb89448SDavid Ahern } 2319*1fb89448SDavid Ahern 2320*1fb89448SDavid Ahern ptr1 = strdup(basename(exec_copy)); 2321225466f1SSrikar Dronamraju if (ptr1) { 2322225466f1SSrikar Dronamraju ptr2 = strpbrk(ptr1, "-._"); 2323225466f1SSrikar Dronamraju if (ptr2) 2324225466f1SSrikar Dronamraju *ptr2 = '\0'; 2325225466f1SSrikar Dronamraju e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP, 2326225466f1SSrikar Dronamraju ptr1); 2327225466f1SSrikar Dronamraju free(ptr1); 2328225466f1SSrikar Dronamraju } 2329*1fb89448SDavid Ahern free(exec_copy); 2330225466f1SSrikar Dronamraju } 2331225466f1SSrikar Dronamraju free(pp->function); 2332225466f1SSrikar Dronamraju pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS); 2333225466f1SSrikar Dronamraju if (!pp->function) { 2334225466f1SSrikar Dronamraju ret = -ENOMEM; 2335225466f1SSrikar Dronamraju pr_warning("Failed to allocate memory by zalloc.\n"); 2336225466f1SSrikar Dronamraju goto out; 2337225466f1SSrikar Dronamraju } 2338225466f1SSrikar Dronamraju e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr); 2339225466f1SSrikar Dronamraju ret = 0; 2340225466f1SSrikar Dronamraju 2341225466f1SSrikar Dronamraju out: 2342225466f1SSrikar Dronamraju if (map) { 2343225466f1SSrikar Dronamraju dso__delete(map->dso); 2344225466f1SSrikar Dronamraju map__delete(map); 2345225466f1SSrikar Dronamraju } 2346225466f1SSrikar Dronamraju if (function) 2347225466f1SSrikar Dronamraju free(function); 2348225466f1SSrikar Dronamraju if (name) 2349225466f1SSrikar Dronamraju free(name); 2350225466f1SSrikar Dronamraju return ret; 2351225466f1SSrikar Dronamraju } 2352