150656eecSMasami Hiramatsu /* 20e60836bSSrikar Dronamraju * probe-event.c : perf-probe definition to probe_events format converter 350656eecSMasami Hiramatsu * 450656eecSMasami Hiramatsu * Written by Masami Hiramatsu <mhiramat@redhat.com> 550656eecSMasami Hiramatsu * 650656eecSMasami Hiramatsu * This program is free software; you can redistribute it and/or modify 750656eecSMasami Hiramatsu * it under the terms of the GNU General Public License as published by 850656eecSMasami Hiramatsu * the Free Software Foundation; either version 2 of the License, or 950656eecSMasami Hiramatsu * (at your option) any later version. 1050656eecSMasami Hiramatsu * 1150656eecSMasami Hiramatsu * This program is distributed in the hope that it will be useful, 1250656eecSMasami Hiramatsu * but WITHOUT ANY WARRANTY; without even the implied warranty of 1350656eecSMasami Hiramatsu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1450656eecSMasami Hiramatsu * GNU General Public License for more details. 1550656eecSMasami Hiramatsu * 1650656eecSMasami Hiramatsu * You should have received a copy of the GNU General Public License 1750656eecSMasami Hiramatsu * along with this program; if not, write to the Free Software 1850656eecSMasami Hiramatsu * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 1950656eecSMasami Hiramatsu * 2050656eecSMasami Hiramatsu */ 2150656eecSMasami Hiramatsu 2250656eecSMasami Hiramatsu #include <sys/utsname.h> 2350656eecSMasami Hiramatsu #include <sys/types.h> 2450656eecSMasami Hiramatsu #include <sys/stat.h> 2550656eecSMasami Hiramatsu #include <fcntl.h> 2650656eecSMasami Hiramatsu #include <errno.h> 2750656eecSMasami Hiramatsu #include <stdio.h> 2850656eecSMasami Hiramatsu #include <unistd.h> 2950656eecSMasami Hiramatsu #include <stdlib.h> 3050656eecSMasami Hiramatsu #include <string.h> 314de189feSMasami Hiramatsu #include <stdarg.h> 324de189feSMasami Hiramatsu #include <limits.h> 33e80711caSMasami Hiramatsu #include <elf.h> 3450656eecSMasami Hiramatsu 3531facc5fSMasami Hiramatsu #include "util.h" 3650656eecSMasami Hiramatsu #include "event.h" 374de189feSMasami Hiramatsu #include "strlist.h" 3850656eecSMasami Hiramatsu #include "debug.h" 3972041334SMasami Hiramatsu #include "cache.h" 40631c9defSMasami Hiramatsu #include "color.h" 41e0faa8d3SMasami Hiramatsu #include "symbol.h" 42e0faa8d3SMasami Hiramatsu #include "thread.h" 43553873e1SBorislav Petkov #include <api/fs/debugfs.h> 4423773ca1SSteven Rostedt (Red Hat) #include <api/fs/tracefs.h> 451d037ca1SIrina Tirdea #include "trace-event.h" /* For __maybe_unused */ 4650656eecSMasami Hiramatsu #include "probe-event.h" 474235b045SMasami Hiramatsu #include "probe-finder.h" 48225466f1SSrikar Dronamraju #include "session.h" 4950656eecSMasami Hiramatsu 5050656eecSMasami Hiramatsu #define MAX_CMDLEN 256 5150656eecSMasami Hiramatsu #define PERFPROBE_GROUP "probe" 5250656eecSMasami Hiramatsu 53f4d7da49SMasami Hiramatsu bool probe_event_dry_run; /* Dry run flag */ 54ddb2f58fSMasami Hiramatsu struct probe_conf probe_conf; 55f4d7da49SMasami Hiramatsu 56146a1439SMasami Hiramatsu #define semantic_error(msg ...) pr_err("Semantic error :" msg) 5750656eecSMasami Hiramatsu 584de189feSMasami Hiramatsu /* If there is no space to write, returns -E2BIG. */ 594de189feSMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...) 6084988450SMasami Hiramatsu __attribute__((format(printf, 3, 4))); 6184988450SMasami Hiramatsu 6284988450SMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...) 634de189feSMasami Hiramatsu { 644de189feSMasami Hiramatsu int ret; 654de189feSMasami Hiramatsu va_list ap; 664de189feSMasami Hiramatsu va_start(ap, format); 674de189feSMasami Hiramatsu ret = vsnprintf(str, size, format, ap); 684de189feSMasami Hiramatsu va_end(ap); 694de189feSMasami Hiramatsu if (ret >= (int)size) 704de189feSMasami Hiramatsu ret = -E2BIG; 714de189feSMasami Hiramatsu return ret; 724de189feSMasami Hiramatsu } 734de189feSMasami Hiramatsu 744b4da7f7SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 75981d05adSMasami Hiramatsu static void clear_probe_trace_event(struct probe_trace_event *tev); 76ee45b6c2SMasami Hiramatsu static struct machine *host_machine; 77e0faa8d3SMasami Hiramatsu 78469b9b88SMasami Hiramatsu /* Initialize symbol maps and path of vmlinux/modules */ 79ee45b6c2SMasami Hiramatsu static int init_symbol_maps(bool user_only) 80e0faa8d3SMasami Hiramatsu { 81146a1439SMasami Hiramatsu int ret; 82146a1439SMasami Hiramatsu 83e0faa8d3SMasami Hiramatsu symbol_conf.sort_by_name = true; 84680d926aSNamhyung Kim symbol_conf.allow_aliases = true; 850a7e6d1bSNamhyung Kim ret = symbol__init(NULL); 86146a1439SMasami Hiramatsu if (ret < 0) { 87146a1439SMasami Hiramatsu pr_debug("Failed to init symbol map.\n"); 88146a1439SMasami Hiramatsu goto out; 89146a1439SMasami Hiramatsu } 90e0faa8d3SMasami Hiramatsu 91ee45b6c2SMasami Hiramatsu if (host_machine || user_only) /* already initialized */ 92ee45b6c2SMasami Hiramatsu return 0; 93d28c6223SArnaldo Carvalho de Melo 94ee45b6c2SMasami Hiramatsu if (symbol_conf.vmlinux_name) 95ee45b6c2SMasami Hiramatsu pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name); 96ee45b6c2SMasami Hiramatsu 97ee45b6c2SMasami Hiramatsu host_machine = machine__new_host(); 98ee45b6c2SMasami Hiramatsu if (!host_machine) { 99ee45b6c2SMasami Hiramatsu pr_debug("machine__new_host() failed.\n"); 100ee45b6c2SMasami Hiramatsu symbol__exit(); 101ee45b6c2SMasami Hiramatsu ret = -1; 102469b9b88SMasami Hiramatsu } 103146a1439SMasami Hiramatsu out: 104146a1439SMasami Hiramatsu if (ret < 0) 105146a1439SMasami Hiramatsu pr_warning("Failed to init vmlinux path.\n"); 106146a1439SMasami Hiramatsu return ret; 107e0faa8d3SMasami Hiramatsu } 108e0faa8d3SMasami Hiramatsu 109ee45b6c2SMasami Hiramatsu static void exit_symbol_maps(void) 110ee45b6c2SMasami Hiramatsu { 111ee45b6c2SMasami Hiramatsu if (host_machine) { 112ee45b6c2SMasami Hiramatsu machine__delete(host_machine); 113ee45b6c2SMasami Hiramatsu host_machine = NULL; 114ee45b6c2SMasami Hiramatsu } 115ee45b6c2SMasami Hiramatsu symbol__exit(); 116ee45b6c2SMasami Hiramatsu } 117ee45b6c2SMasami Hiramatsu 118469b9b88SMasami Hiramatsu static struct symbol *__find_kernel_function_by_name(const char *name, 119469b9b88SMasami Hiramatsu struct map **mapp) 120e0faa8d3SMasami Hiramatsu { 121ee45b6c2SMasami Hiramatsu return machine__find_kernel_function_by_name(host_machine, name, mapp, 122469b9b88SMasami Hiramatsu NULL); 123e0faa8d3SMasami Hiramatsu } 124469b9b88SMasami Hiramatsu 1258f33f7deSMasami Hiramatsu static struct symbol *__find_kernel_function(u64 addr, struct map **mapp) 1268f33f7deSMasami Hiramatsu { 1278f33f7deSMasami Hiramatsu return machine__find_kernel_function(host_machine, addr, mapp, NULL); 1288f33f7deSMasami Hiramatsu } 1298f33f7deSMasami Hiramatsu 1308f33f7deSMasami Hiramatsu static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void) 1318f33f7deSMasami Hiramatsu { 1328f33f7deSMasami Hiramatsu /* kmap->ref_reloc_sym should be set if host_machine is initialized */ 1338f33f7deSMasami Hiramatsu struct kmap *kmap; 1348f33f7deSMasami Hiramatsu 1358f33f7deSMasami Hiramatsu if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0) 1368f33f7deSMasami Hiramatsu return NULL; 1378f33f7deSMasami Hiramatsu 1388f33f7deSMasami Hiramatsu kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]); 139ba92732eSWang Nan if (!kmap) 140ba92732eSWang Nan return NULL; 1418f33f7deSMasami Hiramatsu return kmap->ref_reloc_sym; 1428f33f7deSMasami Hiramatsu } 1438f33f7deSMasami Hiramatsu 1448f33f7deSMasami Hiramatsu static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc) 1458f33f7deSMasami Hiramatsu { 1468f33f7deSMasami Hiramatsu struct ref_reloc_sym *reloc_sym; 1478f33f7deSMasami Hiramatsu struct symbol *sym; 1488f33f7deSMasami Hiramatsu struct map *map; 1498f33f7deSMasami Hiramatsu 1508f33f7deSMasami Hiramatsu /* ref_reloc_sym is just a label. Need a special fix*/ 1518f33f7deSMasami Hiramatsu reloc_sym = kernel_get_ref_reloc_sym(); 1528f33f7deSMasami Hiramatsu if (reloc_sym && strcmp(name, reloc_sym->name) == 0) 1538f33f7deSMasami Hiramatsu return (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr; 1548f33f7deSMasami Hiramatsu else { 1558f33f7deSMasami Hiramatsu sym = __find_kernel_function_by_name(name, &map); 1568f33f7deSMasami Hiramatsu if (sym) 1578f33f7deSMasami Hiramatsu return map->unmap_ip(map, sym->start) - 158f56847c2SHe Kuang ((reloc) ? 0 : map->reloc); 1598f33f7deSMasami Hiramatsu } 1608f33f7deSMasami Hiramatsu return 0; 1618f33f7deSMasami Hiramatsu } 1628f33f7deSMasami Hiramatsu 163e80711caSMasami Hiramatsu static struct map *kernel_get_module_map(const char *module) 164e80711caSMasami Hiramatsu { 165ee45b6c2SMasami Hiramatsu struct map_groups *grp = &host_machine->kmaps; 166*1eee78aeSArnaldo Carvalho de Melo struct maps *maps = &grp->maps[MAP__FUNCTION]; 1674bb7123dSArnaldo Carvalho de Melo struct map *pos; 168e80711caSMasami Hiramatsu 16914a8fd7cSMasami Hiramatsu /* A file path -- this is an offline module */ 17014a8fd7cSMasami Hiramatsu if (module && strchr(module, '/')) 171ee45b6c2SMasami Hiramatsu return machine__new_module(host_machine, 0, module); 17214a8fd7cSMasami Hiramatsu 173e80711caSMasami Hiramatsu if (!module) 174e80711caSMasami Hiramatsu module = "kernel"; 175e80711caSMasami Hiramatsu 1764bb7123dSArnaldo Carvalho de Melo for (pos = maps__first(maps); pos; pos = map__next(pos)) { 177e80711caSMasami Hiramatsu if (strncmp(pos->dso->short_name + 1, module, 178e80711caSMasami Hiramatsu pos->dso->short_name_len - 2) == 0) { 179e80711caSMasami Hiramatsu return pos; 180e80711caSMasami Hiramatsu } 181e80711caSMasami Hiramatsu } 182e80711caSMasami Hiramatsu return NULL; 183e80711caSMasami Hiramatsu } 184e80711caSMasami Hiramatsu 1859b118acaSMasami Hiramatsu static struct map *get_target_map(const char *target, bool user) 1869b118acaSMasami Hiramatsu { 1879b118acaSMasami Hiramatsu /* Init maps of given executable or kernel */ 1889b118acaSMasami Hiramatsu if (user) 1899b118acaSMasami Hiramatsu return dso__new_map(target); 1909b118acaSMasami Hiramatsu else 1919b118acaSMasami Hiramatsu return kernel_get_module_map(target); 1929b118acaSMasami Hiramatsu } 1939b118acaSMasami Hiramatsu 1949b118acaSMasami Hiramatsu static void put_target_map(struct map *map, bool user) 1959b118acaSMasami Hiramatsu { 1969b118acaSMasami Hiramatsu if (map && user) { 1979b118acaSMasami Hiramatsu /* Only the user map needs to be released */ 1989b118acaSMasami Hiramatsu map__delete(map); 1999b118acaSMasami Hiramatsu } 2009b118acaSMasami Hiramatsu } 2019b118acaSMasami Hiramatsu 2029b118acaSMasami Hiramatsu 203419e8738SMasami Hiramatsu static int kernel_get_module_dso(const char *module, struct dso **pdso) 204469b9b88SMasami Hiramatsu { 205469b9b88SMasami Hiramatsu struct dso *dso; 206fd930ff9SFranck Bui-Huu struct map *map; 207fd930ff9SFranck Bui-Huu const char *vmlinux_name; 208419e8738SMasami Hiramatsu int ret = 0; 209469b9b88SMasami Hiramatsu 210469b9b88SMasami Hiramatsu if (module) { 2118fa7d87fSWaiman Long list_for_each_entry(dso, &host_machine->kernel_dsos.head, 2128fa7d87fSWaiman Long node) { 213469b9b88SMasami Hiramatsu if (strncmp(dso->short_name + 1, module, 214469b9b88SMasami Hiramatsu dso->short_name_len - 2) == 0) 215469b9b88SMasami Hiramatsu goto found; 216469b9b88SMasami Hiramatsu } 217469b9b88SMasami Hiramatsu pr_debug("Failed to find module %s.\n", module); 218419e8738SMasami Hiramatsu return -ENOENT; 219fd930ff9SFranck Bui-Huu } 220fd930ff9SFranck Bui-Huu 221ee45b6c2SMasami Hiramatsu map = host_machine->vmlinux_maps[MAP__FUNCTION]; 222fd930ff9SFranck Bui-Huu dso = map->dso; 223fd930ff9SFranck Bui-Huu 224fd930ff9SFranck Bui-Huu vmlinux_name = symbol_conf.vmlinux_name; 225419e8738SMasami Hiramatsu dso->load_errno = 0; 226419e8738SMasami Hiramatsu if (vmlinux_name) 227419e8738SMasami Hiramatsu ret = dso__load_vmlinux(dso, map, vmlinux_name, false, NULL); 228419e8738SMasami Hiramatsu else 229419e8738SMasami Hiramatsu ret = dso__load_vmlinux_path(dso, map, NULL); 230469b9b88SMasami Hiramatsu found: 231419e8738SMasami Hiramatsu *pdso = dso; 232419e8738SMasami Hiramatsu return ret; 233469b9b88SMasami Hiramatsu } 234469b9b88SMasami Hiramatsu 235fb7345bbSMasami Hiramatsu static int convert_exec_to_group(const char *exec, char **result) 236fb7345bbSMasami Hiramatsu { 237fb7345bbSMasami Hiramatsu char *ptr1, *ptr2, *exec_copy; 238fb7345bbSMasami Hiramatsu char buf[64]; 239fb7345bbSMasami Hiramatsu int ret; 240fb7345bbSMasami Hiramatsu 241fb7345bbSMasami Hiramatsu exec_copy = strdup(exec); 242fb7345bbSMasami Hiramatsu if (!exec_copy) 243fb7345bbSMasami Hiramatsu return -ENOMEM; 244fb7345bbSMasami Hiramatsu 245fb7345bbSMasami Hiramatsu ptr1 = basename(exec_copy); 246fb7345bbSMasami Hiramatsu if (!ptr1) { 247fb7345bbSMasami Hiramatsu ret = -EINVAL; 248fb7345bbSMasami Hiramatsu goto out; 249fb7345bbSMasami Hiramatsu } 250fb7345bbSMasami Hiramatsu 251fb7345bbSMasami Hiramatsu ptr2 = strpbrk(ptr1, "-._"); 252fb7345bbSMasami Hiramatsu if (ptr2) 253fb7345bbSMasami Hiramatsu *ptr2 = '\0'; 254fb7345bbSMasami Hiramatsu ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1); 255fb7345bbSMasami Hiramatsu if (ret < 0) 256fb7345bbSMasami Hiramatsu goto out; 257fb7345bbSMasami Hiramatsu 258fb7345bbSMasami Hiramatsu *result = strdup(buf); 259fb7345bbSMasami Hiramatsu ret = *result ? 0 : -ENOMEM; 260fb7345bbSMasami Hiramatsu 261fb7345bbSMasami Hiramatsu out: 262fb7345bbSMasami Hiramatsu free(exec_copy); 263fb7345bbSMasami Hiramatsu return ret; 264fb7345bbSMasami Hiramatsu } 265fb7345bbSMasami Hiramatsu 2669b118acaSMasami Hiramatsu static void clear_perf_probe_point(struct perf_probe_point *pp) 2679b118acaSMasami Hiramatsu { 2689b118acaSMasami Hiramatsu free(pp->file); 2699b118acaSMasami Hiramatsu free(pp->function); 2709b118acaSMasami Hiramatsu free(pp->lazy_line); 2719b118acaSMasami Hiramatsu } 2729b118acaSMasami Hiramatsu 273eb948e50SMasami Hiramatsu static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) 274eb948e50SMasami Hiramatsu { 275eb948e50SMasami Hiramatsu int i; 276eb948e50SMasami Hiramatsu 277eb948e50SMasami Hiramatsu for (i = 0; i < ntevs; i++) 278eb948e50SMasami Hiramatsu clear_probe_trace_event(tevs + i); 279eb948e50SMasami Hiramatsu } 280eb948e50SMasami Hiramatsu 28189fe808aSIngo Molnar #ifdef HAVE_DWARF_SUPPORT 2829b118acaSMasami Hiramatsu /* 2839b118acaSMasami Hiramatsu * Some binaries like glibc have special symbols which are on the symbol 2849b118acaSMasami Hiramatsu * table, but not in the debuginfo. If we can find the address of the 2859b118acaSMasami Hiramatsu * symbol from map, we can translate the address back to the probe point. 2869b118acaSMasami Hiramatsu */ 2879b118acaSMasami Hiramatsu static int find_alternative_probe_point(struct debuginfo *dinfo, 2889b118acaSMasami Hiramatsu struct perf_probe_point *pp, 2899b118acaSMasami Hiramatsu struct perf_probe_point *result, 2909b118acaSMasami Hiramatsu const char *target, bool uprobes) 2919b118acaSMasami Hiramatsu { 2929b118acaSMasami Hiramatsu struct map *map = NULL; 2939b118acaSMasami Hiramatsu struct symbol *sym; 2949b118acaSMasami Hiramatsu u64 address = 0; 2959b118acaSMasami Hiramatsu int ret = -ENOENT; 2969b118acaSMasami Hiramatsu 2979b118acaSMasami Hiramatsu /* This can work only for function-name based one */ 2989b118acaSMasami Hiramatsu if (!pp->function || pp->file) 2999b118acaSMasami Hiramatsu return -ENOTSUP; 3009b118acaSMasami Hiramatsu 3019b118acaSMasami Hiramatsu map = get_target_map(target, uprobes); 3029b118acaSMasami Hiramatsu if (!map) 3039b118acaSMasami Hiramatsu return -EINVAL; 3049b118acaSMasami Hiramatsu 3059b118acaSMasami Hiramatsu /* Find the address of given function */ 3069b118acaSMasami Hiramatsu map__for_each_symbol_by_name(map, pp->function, sym) { 307e6d7c91cSMasami Hiramatsu if (uprobes) 3089b118acaSMasami Hiramatsu address = sym->start; 309e6d7c91cSMasami Hiramatsu else 310e6d7c91cSMasami Hiramatsu address = map->unmap_ip(map, sym->start); 3119b118acaSMasami Hiramatsu break; 3129b118acaSMasami Hiramatsu } 3139b118acaSMasami Hiramatsu if (!address) { 3149b118acaSMasami Hiramatsu ret = -ENOENT; 3159b118acaSMasami Hiramatsu goto out; 3169b118acaSMasami Hiramatsu } 317f6c15621SWang Nan pr_debug("Symbol %s address found : %" PRIx64 "\n", 318f6c15621SWang Nan pp->function, address); 3199b118acaSMasami Hiramatsu 3209b118acaSMasami Hiramatsu ret = debuginfo__find_probe_point(dinfo, (unsigned long)address, 3219b118acaSMasami Hiramatsu result); 3229b118acaSMasami Hiramatsu if (ret <= 0) 3239b118acaSMasami Hiramatsu ret = (!ret) ? -ENOENT : ret; 3249b118acaSMasami Hiramatsu else { 3259b118acaSMasami Hiramatsu result->offset += pp->offset; 3269b118acaSMasami Hiramatsu result->line += pp->line; 3279d7b45c5SHe Kuang result->retprobe = pp->retprobe; 3289b118acaSMasami Hiramatsu ret = 0; 3299b118acaSMasami Hiramatsu } 3309b118acaSMasami Hiramatsu 3319b118acaSMasami Hiramatsu out: 3329b118acaSMasami Hiramatsu put_target_map(map, uprobes); 3339b118acaSMasami Hiramatsu return ret; 3349b118acaSMasami Hiramatsu 3359b118acaSMasami Hiramatsu } 3369b118acaSMasami Hiramatsu 3379b118acaSMasami Hiramatsu static int get_alternative_probe_event(struct debuginfo *dinfo, 3389b118acaSMasami Hiramatsu struct perf_probe_event *pev, 33944225521SMasami Hiramatsu struct perf_probe_point *tmp) 3409b118acaSMasami Hiramatsu { 3419b118acaSMasami Hiramatsu int ret; 3429b118acaSMasami Hiramatsu 3439b118acaSMasami Hiramatsu memcpy(tmp, &pev->point, sizeof(*tmp)); 3449b118acaSMasami Hiramatsu memset(&pev->point, 0, sizeof(pev->point)); 3459b118acaSMasami Hiramatsu ret = find_alternative_probe_point(dinfo, tmp, &pev->point, 34644225521SMasami Hiramatsu pev->target, pev->uprobes); 3479b118acaSMasami Hiramatsu if (ret < 0) 3489b118acaSMasami Hiramatsu memcpy(&pev->point, tmp, sizeof(*tmp)); 3499b118acaSMasami Hiramatsu 3509b118acaSMasami Hiramatsu return ret; 3519b118acaSMasami Hiramatsu } 352a15ad2f5SMasami Hiramatsu 353811dd2aeSMasami Hiramatsu static int get_alternative_line_range(struct debuginfo *dinfo, 354811dd2aeSMasami Hiramatsu struct line_range *lr, 355811dd2aeSMasami Hiramatsu const char *target, bool user) 356811dd2aeSMasami Hiramatsu { 3576d4a4896SDavid Ahern struct perf_probe_point pp = { .function = lr->function, 3586d4a4896SDavid Ahern .file = lr->file, 3596d4a4896SDavid Ahern .line = lr->start }; 3606d4a4896SDavid Ahern struct perf_probe_point result; 361811dd2aeSMasami Hiramatsu int ret, len = 0; 362811dd2aeSMasami Hiramatsu 3636d4a4896SDavid Ahern memset(&result, 0, sizeof(result)); 3646d4a4896SDavid Ahern 365811dd2aeSMasami Hiramatsu if (lr->end != INT_MAX) 366811dd2aeSMasami Hiramatsu len = lr->end - lr->start; 367811dd2aeSMasami Hiramatsu ret = find_alternative_probe_point(dinfo, &pp, &result, 368811dd2aeSMasami Hiramatsu target, user); 369811dd2aeSMasami Hiramatsu if (!ret) { 370811dd2aeSMasami Hiramatsu lr->function = result.function; 371811dd2aeSMasami Hiramatsu lr->file = result.file; 372811dd2aeSMasami Hiramatsu lr->start = result.line; 373811dd2aeSMasami Hiramatsu if (lr->end != INT_MAX) 374811dd2aeSMasami Hiramatsu lr->end = lr->start + len; 375811dd2aeSMasami Hiramatsu clear_perf_probe_point(&pp); 376811dd2aeSMasami Hiramatsu } 377811dd2aeSMasami Hiramatsu return ret; 378811dd2aeSMasami Hiramatsu } 379811dd2aeSMasami Hiramatsu 380ff741783SMasami Hiramatsu /* Open new debuginfo of given module */ 38192561cb7SMasami Hiramatsu static struct debuginfo *open_debuginfo(const char *module, bool silent) 382469b9b88SMasami Hiramatsu { 383a15ad2f5SMasami Hiramatsu const char *path = module; 384419e8738SMasami Hiramatsu char reason[STRERR_BUFSIZE]; 385419e8738SMasami Hiramatsu struct debuginfo *ret = NULL; 386419e8738SMasami Hiramatsu struct dso *dso = NULL; 387419e8738SMasami Hiramatsu int err; 38814a8fd7cSMasami Hiramatsu 389a15ad2f5SMasami Hiramatsu if (!module || !strchr(module, '/')) { 390419e8738SMasami Hiramatsu err = kernel_get_module_dso(module, &dso); 391419e8738SMasami Hiramatsu if (err < 0) { 392419e8738SMasami Hiramatsu if (!dso || dso->load_errno == 0) { 393419e8738SMasami Hiramatsu if (!strerror_r(-err, reason, STRERR_BUFSIZE)) 394419e8738SMasami Hiramatsu strcpy(reason, "(unknown)"); 395419e8738SMasami Hiramatsu } else 396419e8738SMasami Hiramatsu dso__strerror_load(dso, reason, STRERR_BUFSIZE); 39792561cb7SMasami Hiramatsu if (!silent) 398419e8738SMasami Hiramatsu pr_err("Failed to find the path for %s: %s\n", 399419e8738SMasami Hiramatsu module ?: "kernel", reason); 400ff741783SMasami Hiramatsu return NULL; 401469b9b88SMasami Hiramatsu } 402419e8738SMasami Hiramatsu path = dso->long_name; 40314a8fd7cSMasami Hiramatsu } 40492561cb7SMasami Hiramatsu ret = debuginfo__new(path); 40592561cb7SMasami Hiramatsu if (!ret && !silent) { 40692561cb7SMasami Hiramatsu pr_warning("The %s file has no debug information.\n", path); 40792561cb7SMasami Hiramatsu if (!module || !strtailcmp(path, ".ko")) 40892561cb7SMasami Hiramatsu pr_warning("Rebuild with CONFIG_DEBUG_INFO=y, "); 40992561cb7SMasami Hiramatsu else 41092561cb7SMasami Hiramatsu pr_warning("Rebuild with -g, "); 41192561cb7SMasami Hiramatsu pr_warning("or install an appropriate debuginfo package.\n"); 412e0faa8d3SMasami Hiramatsu } 41392561cb7SMasami Hiramatsu return ret; 41492561cb7SMasami Hiramatsu } 41592561cb7SMasami Hiramatsu 4164b4da7f7SMasami Hiramatsu 41799ca4233SMasami Hiramatsu static int get_text_start_address(const char *exec, unsigned long *address) 41899ca4233SMasami Hiramatsu { 41999ca4233SMasami Hiramatsu Elf *elf; 42099ca4233SMasami Hiramatsu GElf_Ehdr ehdr; 42199ca4233SMasami Hiramatsu GElf_Shdr shdr; 42299ca4233SMasami Hiramatsu int fd, ret = -ENOENT; 42399ca4233SMasami Hiramatsu 42499ca4233SMasami Hiramatsu fd = open(exec, O_RDONLY); 42599ca4233SMasami Hiramatsu if (fd < 0) 42699ca4233SMasami Hiramatsu return -errno; 42799ca4233SMasami Hiramatsu 42899ca4233SMasami Hiramatsu elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 42999ca4233SMasami Hiramatsu if (elf == NULL) 43099ca4233SMasami Hiramatsu return -EINVAL; 43199ca4233SMasami Hiramatsu 43299ca4233SMasami Hiramatsu if (gelf_getehdr(elf, &ehdr) == NULL) 43399ca4233SMasami Hiramatsu goto out; 43499ca4233SMasami Hiramatsu 43599ca4233SMasami Hiramatsu if (!elf_section_by_name(elf, &ehdr, &shdr, ".text", NULL)) 43699ca4233SMasami Hiramatsu goto out; 43799ca4233SMasami Hiramatsu 43899ca4233SMasami Hiramatsu *address = shdr.sh_addr - shdr.sh_offset; 43999ca4233SMasami Hiramatsu ret = 0; 44099ca4233SMasami Hiramatsu out: 44199ca4233SMasami Hiramatsu elf_end(elf); 44299ca4233SMasami Hiramatsu return ret; 44399ca4233SMasami Hiramatsu } 44499ca4233SMasami Hiramatsu 4455a6f6314SMasami Hiramatsu /* 4465a6f6314SMasami Hiramatsu * Convert trace point to probe point with debuginfo 4475a6f6314SMasami Hiramatsu */ 4485a6f6314SMasami Hiramatsu static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp, 4495a6f6314SMasami Hiramatsu struct perf_probe_point *pp, 4505a6f6314SMasami Hiramatsu bool is_kprobe) 4515a6f6314SMasami Hiramatsu { 4525a6f6314SMasami Hiramatsu struct debuginfo *dinfo = NULL; 4535a6f6314SMasami Hiramatsu unsigned long stext = 0; 4545a6f6314SMasami Hiramatsu u64 addr = tp->address; 4555a6f6314SMasami Hiramatsu int ret = -ENOENT; 4565a6f6314SMasami Hiramatsu 4575a6f6314SMasami Hiramatsu /* convert the address to dwarf address */ 4585a6f6314SMasami Hiramatsu if (!is_kprobe) { 4595a6f6314SMasami Hiramatsu if (!addr) { 4605a6f6314SMasami Hiramatsu ret = -EINVAL; 4615a6f6314SMasami Hiramatsu goto error; 4625a6f6314SMasami Hiramatsu } 4635a6f6314SMasami Hiramatsu ret = get_text_start_address(tp->module, &stext); 4645a6f6314SMasami Hiramatsu if (ret < 0) 4655a6f6314SMasami Hiramatsu goto error; 4665a6f6314SMasami Hiramatsu addr += stext; 4675a6f6314SMasami Hiramatsu } else { 4685a6f6314SMasami Hiramatsu addr = kernel_get_symbol_address_by_name(tp->symbol, false); 4695a6f6314SMasami Hiramatsu if (addr == 0) 4705a6f6314SMasami Hiramatsu goto error; 4715a6f6314SMasami Hiramatsu addr += tp->offset; 4725a6f6314SMasami Hiramatsu } 4735a6f6314SMasami Hiramatsu 4745a6f6314SMasami Hiramatsu pr_debug("try to find information at %" PRIx64 " in %s\n", addr, 4755a6f6314SMasami Hiramatsu tp->module ? : "kernel"); 4765a6f6314SMasami Hiramatsu 47792561cb7SMasami Hiramatsu dinfo = open_debuginfo(tp->module, verbose == 0); 4785a6f6314SMasami Hiramatsu if (dinfo) { 4795a6f6314SMasami Hiramatsu ret = debuginfo__find_probe_point(dinfo, 4805a6f6314SMasami Hiramatsu (unsigned long)addr, pp); 4815a6f6314SMasami Hiramatsu debuginfo__delete(dinfo); 48292561cb7SMasami Hiramatsu } else 4835a6f6314SMasami Hiramatsu ret = -ENOENT; 4845a6f6314SMasami Hiramatsu 4855a6f6314SMasami Hiramatsu if (ret > 0) { 4865a6f6314SMasami Hiramatsu pp->retprobe = tp->retprobe; 4875a6f6314SMasami Hiramatsu return 0; 4885a6f6314SMasami Hiramatsu } 4895a6f6314SMasami Hiramatsu error: 4905a6f6314SMasami Hiramatsu pr_debug("Failed to find corresponding probes from debuginfo.\n"); 4915a6f6314SMasami Hiramatsu return ret ? : -ENOENT; 4925a6f6314SMasami Hiramatsu } 4935a6f6314SMasami Hiramatsu 494fb7345bbSMasami Hiramatsu static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, 495fb7345bbSMasami Hiramatsu int ntevs, const char *exec) 496fb7345bbSMasami Hiramatsu { 497fb7345bbSMasami Hiramatsu int i, ret = 0; 498eb948e50SMasami Hiramatsu unsigned long stext = 0; 499fb7345bbSMasami Hiramatsu 500fb7345bbSMasami Hiramatsu if (!exec) 501fb7345bbSMasami Hiramatsu return 0; 502fb7345bbSMasami Hiramatsu 503fb7345bbSMasami Hiramatsu ret = get_text_start_address(exec, &stext); 504fb7345bbSMasami Hiramatsu if (ret < 0) 505fb7345bbSMasami Hiramatsu return ret; 506fb7345bbSMasami Hiramatsu 507fb7345bbSMasami Hiramatsu for (i = 0; i < ntevs && ret >= 0; i++) { 508981a2379SMasami Hiramatsu /* point.address is the addres of point.symbol + point.offset */ 509eb948e50SMasami Hiramatsu tevs[i].point.address -= stext; 510fb7345bbSMasami Hiramatsu tevs[i].point.module = strdup(exec); 511eb948e50SMasami Hiramatsu if (!tevs[i].point.module) { 512fb7345bbSMasami Hiramatsu ret = -ENOMEM; 513fb7345bbSMasami Hiramatsu break; 514fb7345bbSMasami Hiramatsu } 515fb7345bbSMasami Hiramatsu tevs[i].uprobes = true; 516fb7345bbSMasami Hiramatsu } 517fb7345bbSMasami Hiramatsu 518fb7345bbSMasami Hiramatsu return ret; 519fb7345bbSMasami Hiramatsu } 520fb7345bbSMasami Hiramatsu 521190b57fcSMasami Hiramatsu static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, 522190b57fcSMasami Hiramatsu int ntevs, const char *module) 523190b57fcSMasami Hiramatsu { 52414a8fd7cSMasami Hiramatsu int i, ret = 0; 52514a8fd7cSMasami Hiramatsu char *tmp; 52614a8fd7cSMasami Hiramatsu 52714a8fd7cSMasami Hiramatsu if (!module) 52814a8fd7cSMasami Hiramatsu return 0; 52914a8fd7cSMasami Hiramatsu 53014a8fd7cSMasami Hiramatsu tmp = strrchr(module, '/'); 53114a8fd7cSMasami Hiramatsu if (tmp) { 53214a8fd7cSMasami Hiramatsu /* This is a module path -- get the module name */ 53314a8fd7cSMasami Hiramatsu module = strdup(tmp + 1); 53414a8fd7cSMasami Hiramatsu if (!module) 53514a8fd7cSMasami Hiramatsu return -ENOMEM; 53614a8fd7cSMasami Hiramatsu tmp = strchr(module, '.'); 53714a8fd7cSMasami Hiramatsu if (tmp) 53814a8fd7cSMasami Hiramatsu *tmp = '\0'; 53914a8fd7cSMasami Hiramatsu tmp = (char *)module; /* For free() */ 54014a8fd7cSMasami Hiramatsu } 54114a8fd7cSMasami Hiramatsu 542190b57fcSMasami Hiramatsu for (i = 0; i < ntevs; i++) { 543190b57fcSMasami Hiramatsu tevs[i].point.module = strdup(module); 54414a8fd7cSMasami Hiramatsu if (!tevs[i].point.module) { 54514a8fd7cSMasami Hiramatsu ret = -ENOMEM; 54614a8fd7cSMasami Hiramatsu break; 547190b57fcSMasami Hiramatsu } 54814a8fd7cSMasami Hiramatsu } 54914a8fd7cSMasami Hiramatsu 55014a8fd7cSMasami Hiramatsu free(tmp); 55114a8fd7cSMasami Hiramatsu return ret; 552190b57fcSMasami Hiramatsu } 553190b57fcSMasami Hiramatsu 554dfef99cdSMasami Hiramatsu /* Post processing the probe events */ 555dfef99cdSMasami Hiramatsu static int post_process_probe_trace_events(struct probe_trace_event *tevs, 556dfef99cdSMasami Hiramatsu int ntevs, const char *module, 557dfef99cdSMasami Hiramatsu bool uprobe) 558dfef99cdSMasami Hiramatsu { 559dfef99cdSMasami Hiramatsu struct ref_reloc_sym *reloc_sym; 5605a51fcd1SMasami Hiramatsu u64 etext_addr; 561dfef99cdSMasami Hiramatsu char *tmp; 5625a51fcd1SMasami Hiramatsu int i, skipped = 0; 563dfef99cdSMasami Hiramatsu 564dfef99cdSMasami Hiramatsu if (uprobe) 565dfef99cdSMasami Hiramatsu return add_exec_to_probe_trace_events(tevs, ntevs, module); 566dfef99cdSMasami Hiramatsu 567dfef99cdSMasami Hiramatsu /* Note that currently ref_reloc_sym based probe is not for drivers */ 568dfef99cdSMasami Hiramatsu if (module) 569dfef99cdSMasami Hiramatsu return add_module_to_probe_trace_events(tevs, ntevs, module); 570dfef99cdSMasami Hiramatsu 5718f33f7deSMasami Hiramatsu reloc_sym = kernel_get_ref_reloc_sym(); 572dfef99cdSMasami Hiramatsu if (!reloc_sym) { 573dfef99cdSMasami Hiramatsu pr_warning("Relocated base symbol is not found!\n"); 574dfef99cdSMasami Hiramatsu return -EINVAL; 575dfef99cdSMasami Hiramatsu } 5765a51fcd1SMasami Hiramatsu /* Get the address of _etext for checking non-probable text symbol */ 5775a51fcd1SMasami Hiramatsu etext_addr = kernel_get_symbol_address_by_name("_etext", false); 578dfef99cdSMasami Hiramatsu 579dfef99cdSMasami Hiramatsu for (i = 0; i < ntevs; i++) { 58025dd9171SNamhyung Kim if (tevs[i].point.address && !tevs[i].point.retprobe) { 5815a51fcd1SMasami Hiramatsu /* If we found a wrong one, mark it by NULL symbol */ 5825a51fcd1SMasami Hiramatsu if (etext_addr < tevs[i].point.address) { 5835a51fcd1SMasami Hiramatsu pr_warning("%s+%lu is out of .text, skip it.\n", 5845a51fcd1SMasami Hiramatsu tevs[i].point.symbol, tevs[i].point.offset); 5855a51fcd1SMasami Hiramatsu tmp = NULL; 5865a51fcd1SMasami Hiramatsu skipped++; 5875a51fcd1SMasami Hiramatsu } else { 588dfef99cdSMasami Hiramatsu tmp = strdup(reloc_sym->name); 589dfef99cdSMasami Hiramatsu if (!tmp) 590dfef99cdSMasami Hiramatsu return -ENOMEM; 5915a51fcd1SMasami Hiramatsu } 5924c859351SMasami Hiramatsu /* If we have no realname, use symbol for it */ 5934c859351SMasami Hiramatsu if (!tevs[i].point.realname) 5944c859351SMasami Hiramatsu tevs[i].point.realname = tevs[i].point.symbol; 5954c859351SMasami Hiramatsu else 596dfef99cdSMasami Hiramatsu free(tevs[i].point.symbol); 597dfef99cdSMasami Hiramatsu tevs[i].point.symbol = tmp; 598dfef99cdSMasami Hiramatsu tevs[i].point.offset = tevs[i].point.address - 599dfef99cdSMasami Hiramatsu reloc_sym->unrelocated_addr; 600dfef99cdSMasami Hiramatsu } 601dfef99cdSMasami Hiramatsu } 6025a51fcd1SMasami Hiramatsu return skipped; 603dfef99cdSMasami Hiramatsu } 604dfef99cdSMasami Hiramatsu 6054b4da7f7SMasami Hiramatsu /* Try to find perf_probe_event with debuginfo */ 6060e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 607ddb2f58fSMasami Hiramatsu struct probe_trace_event **tevs) 6084b4da7f7SMasami Hiramatsu { 6094b4da7f7SMasami Hiramatsu bool need_dwarf = perf_probe_event_need_dwarf(pev); 6109b118acaSMasami Hiramatsu struct perf_probe_point tmp; 611225466f1SSrikar Dronamraju struct debuginfo *dinfo; 612190b57fcSMasami Hiramatsu int ntevs, ret = 0; 6134b4da7f7SMasami Hiramatsu 61444225521SMasami Hiramatsu dinfo = open_debuginfo(pev->target, !need_dwarf); 615ff741783SMasami Hiramatsu if (!dinfo) { 61692561cb7SMasami Hiramatsu if (need_dwarf) 617ff741783SMasami Hiramatsu return -ENOENT; 618ff741783SMasami Hiramatsu pr_debug("Could not open debuginfo. Try to use symbols.\n"); 6194b4da7f7SMasami Hiramatsu return 0; 6204b4da7f7SMasami Hiramatsu } 6214b4da7f7SMasami Hiramatsu 622dfef99cdSMasami Hiramatsu pr_debug("Try to find probe point from debuginfo.\n"); 623ff741783SMasami Hiramatsu /* Searching trace events corresponding to a probe event */ 624ddb2f58fSMasami Hiramatsu ntevs = debuginfo__find_trace_events(dinfo, pev, tevs); 625ff741783SMasami Hiramatsu 6269b118acaSMasami Hiramatsu if (ntevs == 0) { /* Not found, retry with an alternative */ 62744225521SMasami Hiramatsu ret = get_alternative_probe_event(dinfo, pev, &tmp); 6289b118acaSMasami Hiramatsu if (!ret) { 629ddb2f58fSMasami Hiramatsu ntevs = debuginfo__find_trace_events(dinfo, pev, tevs); 6309b118acaSMasami Hiramatsu /* 6319b118acaSMasami Hiramatsu * Write back to the original probe_event for 6329b118acaSMasami Hiramatsu * setting appropriate (user given) event name 6339b118acaSMasami Hiramatsu */ 6349b118acaSMasami Hiramatsu clear_perf_probe_point(&pev->point); 6359b118acaSMasami Hiramatsu memcpy(&pev->point, &tmp, sizeof(tmp)); 6369b118acaSMasami Hiramatsu } 6379b118acaSMasami Hiramatsu } 6389b118acaSMasami Hiramatsu 639ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 6404b4da7f7SMasami Hiramatsu 641146a1439SMasami Hiramatsu if (ntevs > 0) { /* Succeeded to find trace events */ 642dfef99cdSMasami Hiramatsu pr_debug("Found %d probe_trace_events.\n", ntevs); 643dfef99cdSMasami Hiramatsu ret = post_process_probe_trace_events(*tevs, ntevs, 64444225521SMasami Hiramatsu pev->target, pev->uprobes); 6455a51fcd1SMasami Hiramatsu if (ret < 0 || ret == ntevs) { 646981d05adSMasami Hiramatsu clear_probe_trace_events(*tevs, ntevs); 647981d05adSMasami Hiramatsu zfree(tevs); 648981d05adSMasami Hiramatsu } 6495a51fcd1SMasami Hiramatsu if (ret != ntevs) 650190b57fcSMasami Hiramatsu return ret < 0 ? ret : ntevs; 6515a51fcd1SMasami Hiramatsu ntevs = 0; 6525a51fcd1SMasami Hiramatsu /* Fall through */ 653146a1439SMasami Hiramatsu } 6544b4da7f7SMasami Hiramatsu 655146a1439SMasami Hiramatsu if (ntevs == 0) { /* No error but failed to find probe point. */ 6560687eba7SMasami Hiramatsu pr_warning("Probe point '%s' not found.\n", 6574b4da7f7SMasami Hiramatsu synthesize_perf_probe_point(&pev->point)); 658146a1439SMasami Hiramatsu return -ENOENT; 659146a1439SMasami Hiramatsu } 660146a1439SMasami Hiramatsu /* Error path : ntevs < 0 */ 66115eca306SMasami Hiramatsu pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); 66215eca306SMasami Hiramatsu if (ntevs == -EBADF) { 66315eca306SMasami Hiramatsu pr_warning("Warning: No dwarf info found in the vmlinux - " 66415eca306SMasami Hiramatsu "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); 66515eca306SMasami Hiramatsu if (!need_dwarf) { 6660e43e5d2SMasami Hiramatsu pr_debug("Trying to use symbols.\n"); 6674b4da7f7SMasami Hiramatsu return 0; 6684b4da7f7SMasami Hiramatsu } 66915eca306SMasami Hiramatsu } 67015eca306SMasami Hiramatsu return ntevs; 67115eca306SMasami Hiramatsu } 6724b4da7f7SMasami Hiramatsu 6734b4da7f7SMasami Hiramatsu #define LINEBUF_SIZE 256 6744b4da7f7SMasami Hiramatsu #define NR_ADDITIONAL_LINES 2 6754b4da7f7SMasami Hiramatsu 676fde52dbdSFranck Bui-Huu static int __show_one_line(FILE *fp, int l, bool skip, bool show_num) 6774b4da7f7SMasami Hiramatsu { 6785f03cba4SMasami Hiramatsu char buf[LINEBUF_SIZE], sbuf[STRERR_BUFSIZE]; 679befe3414SFranck Bui-Huu const char *color = show_num ? "" : PERF_COLOR_BLUE; 680befe3414SFranck Bui-Huu const char *prefix = NULL; 6814b4da7f7SMasami Hiramatsu 682befe3414SFranck Bui-Huu do { 6834b4da7f7SMasami Hiramatsu if (fgets(buf, LINEBUF_SIZE, fp) == NULL) 6844b4da7f7SMasami Hiramatsu goto error; 685befe3414SFranck Bui-Huu if (skip) 686befe3414SFranck Bui-Huu continue; 687befe3414SFranck Bui-Huu if (!prefix) { 688befe3414SFranck Bui-Huu prefix = show_num ? "%7d " : " "; 689befe3414SFranck Bui-Huu color_fprintf(stdout, color, prefix, l); 6904b4da7f7SMasami Hiramatsu } 691befe3414SFranck Bui-Huu color_fprintf(stdout, color, "%s", buf); 6924b4da7f7SMasami Hiramatsu 693befe3414SFranck Bui-Huu } while (strchr(buf, '\n') == NULL); 694146a1439SMasami Hiramatsu 695fde52dbdSFranck Bui-Huu return 1; 6964b4da7f7SMasami Hiramatsu error: 697fde52dbdSFranck Bui-Huu if (ferror(fp)) { 6985f03cba4SMasami Hiramatsu pr_warning("File read error: %s\n", 6995f03cba4SMasami Hiramatsu strerror_r(errno, sbuf, sizeof(sbuf))); 700146a1439SMasami Hiramatsu return -1; 7014b4da7f7SMasami Hiramatsu } 702fde52dbdSFranck Bui-Huu return 0; 703fde52dbdSFranck Bui-Huu } 704fde52dbdSFranck Bui-Huu 705fde52dbdSFranck Bui-Huu static int _show_one_line(FILE *fp, int l, bool skip, bool show_num) 706fde52dbdSFranck Bui-Huu { 707fde52dbdSFranck Bui-Huu int rv = __show_one_line(fp, l, skip, show_num); 708fde52dbdSFranck Bui-Huu if (rv == 0) { 709fde52dbdSFranck Bui-Huu pr_warning("Source file is shorter than expected.\n"); 710fde52dbdSFranck Bui-Huu rv = -1; 711fde52dbdSFranck Bui-Huu } 712fde52dbdSFranck Bui-Huu return rv; 713fde52dbdSFranck Bui-Huu } 714fde52dbdSFranck Bui-Huu 715fde52dbdSFranck Bui-Huu #define show_one_line_with_num(f,l) _show_one_line(f,l,false,true) 716fde52dbdSFranck Bui-Huu #define show_one_line(f,l) _show_one_line(f,l,false,false) 717fde52dbdSFranck Bui-Huu #define skip_one_line(f,l) _show_one_line(f,l,true,false) 718fde52dbdSFranck Bui-Huu #define show_one_line_or_eof(f,l) __show_one_line(f,l,false,false) 7194b4da7f7SMasami Hiramatsu 7204b4da7f7SMasami Hiramatsu /* 7214b4da7f7SMasami Hiramatsu * Show line-range always requires debuginfo to find source file and 7224b4da7f7SMasami Hiramatsu * line number. 7234b4da7f7SMasami Hiramatsu */ 724811dd2aeSMasami Hiramatsu static int __show_line_range(struct line_range *lr, const char *module, 725811dd2aeSMasami Hiramatsu bool user) 7264b4da7f7SMasami Hiramatsu { 727d3b63d7aSMasami Hiramatsu int l = 1; 7285a62257aSMasami Hiramatsu struct int_node *ln; 729ff741783SMasami Hiramatsu struct debuginfo *dinfo; 7304b4da7f7SMasami Hiramatsu FILE *fp; 731ff741783SMasami Hiramatsu int ret; 7327cf0b79eSMasami Hiramatsu char *tmp; 7335f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 7344b4da7f7SMasami Hiramatsu 7354b4da7f7SMasami Hiramatsu /* Search a line range */ 73692561cb7SMasami Hiramatsu dinfo = open_debuginfo(module, false); 73792561cb7SMasami Hiramatsu if (!dinfo) 738ff741783SMasami Hiramatsu return -ENOENT; 739146a1439SMasami Hiramatsu 740ff741783SMasami Hiramatsu ret = debuginfo__find_line_range(dinfo, lr); 741811dd2aeSMasami Hiramatsu if (!ret) { /* Not found, retry with an alternative */ 742811dd2aeSMasami Hiramatsu ret = get_alternative_line_range(dinfo, lr, module, user); 743811dd2aeSMasami Hiramatsu if (!ret) 744811dd2aeSMasami Hiramatsu ret = debuginfo__find_line_range(dinfo, lr); 745811dd2aeSMasami Hiramatsu } 746ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 7475ee05b88SMasami Hiramatsu if (ret == 0 || ret == -ENOENT) { 748146a1439SMasami Hiramatsu pr_warning("Specified source line is not found.\n"); 749146a1439SMasami Hiramatsu return -ENOENT; 750146a1439SMasami Hiramatsu } else if (ret < 0) { 7515ee05b88SMasami Hiramatsu pr_warning("Debuginfo analysis failed.\n"); 752146a1439SMasami Hiramatsu return ret; 753146a1439SMasami Hiramatsu } 7544b4da7f7SMasami Hiramatsu 7557cf0b79eSMasami Hiramatsu /* Convert source file path */ 7567cf0b79eSMasami Hiramatsu tmp = lr->path; 7576a330a3cSMasami Hiramatsu ret = get_real_path(tmp, lr->comp_dir, &lr->path); 758a78604deSHe Kuang 759a78604deSHe Kuang /* Free old path when new path is assigned */ 760a78604deSHe Kuang if (tmp != lr->path) 761a78604deSHe Kuang free(tmp); 762a78604deSHe Kuang 7637cf0b79eSMasami Hiramatsu if (ret < 0) { 7645ee05b88SMasami Hiramatsu pr_warning("Failed to find source file path.\n"); 7657cf0b79eSMasami Hiramatsu return ret; 7667cf0b79eSMasami Hiramatsu } 7677cf0b79eSMasami Hiramatsu 7684b4da7f7SMasami Hiramatsu setup_pager(); 7694b4da7f7SMasami Hiramatsu 7704b4da7f7SMasami Hiramatsu if (lr->function) 7718737ebdeSMasami Hiramatsu fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path, 7724b4da7f7SMasami Hiramatsu lr->start - lr->offset); 7734b4da7f7SMasami Hiramatsu else 77462c15fc4SFranck Bui-Huu fprintf(stdout, "<%s:%d>\n", lr->path, lr->start); 7754b4da7f7SMasami Hiramatsu 7764b4da7f7SMasami Hiramatsu fp = fopen(lr->path, "r"); 777146a1439SMasami Hiramatsu if (fp == NULL) { 778146a1439SMasami Hiramatsu pr_warning("Failed to open %s: %s\n", lr->path, 7795f03cba4SMasami Hiramatsu strerror_r(errno, sbuf, sizeof(sbuf))); 780146a1439SMasami Hiramatsu return -errno; 781146a1439SMasami Hiramatsu } 7824b4da7f7SMasami Hiramatsu /* Skip to starting line number */ 78344b81e92SFranck Bui-Huu while (l < lr->start) { 784fde52dbdSFranck Bui-Huu ret = skip_one_line(fp, l++); 785146a1439SMasami Hiramatsu if (ret < 0) 786146a1439SMasami Hiramatsu goto end; 78744b81e92SFranck Bui-Huu } 7884b4da7f7SMasami Hiramatsu 7895a62257aSMasami Hiramatsu intlist__for_each(ln, lr->line_list) { 7905a62257aSMasami Hiramatsu for (; ln->i > l; l++) { 791fde52dbdSFranck Bui-Huu ret = show_one_line(fp, l - lr->offset); 79244b81e92SFranck Bui-Huu if (ret < 0) 79344b81e92SFranck Bui-Huu goto end; 79444b81e92SFranck Bui-Huu } 795fde52dbdSFranck Bui-Huu ret = show_one_line_with_num(fp, l++ - lr->offset); 796146a1439SMasami Hiramatsu if (ret < 0) 797146a1439SMasami Hiramatsu goto end; 7984b4da7f7SMasami Hiramatsu } 7994b4da7f7SMasami Hiramatsu 8004b4da7f7SMasami Hiramatsu if (lr->end == INT_MAX) 8014b4da7f7SMasami Hiramatsu lr->end = l + NR_ADDITIONAL_LINES; 802fde52dbdSFranck Bui-Huu while (l <= lr->end) { 803fde52dbdSFranck Bui-Huu ret = show_one_line_or_eof(fp, l++ - lr->offset); 804fde52dbdSFranck Bui-Huu if (ret <= 0) 80544b81e92SFranck Bui-Huu break; 80644b81e92SFranck Bui-Huu } 807146a1439SMasami Hiramatsu end: 8084b4da7f7SMasami Hiramatsu fclose(fp); 809146a1439SMasami Hiramatsu return ret; 8104b4da7f7SMasami Hiramatsu } 8114b4da7f7SMasami Hiramatsu 8122b394bc4SMasami Hiramatsu int show_line_range(struct line_range *lr, const char *module, bool user) 813ee45b6c2SMasami Hiramatsu { 814ee45b6c2SMasami Hiramatsu int ret; 815ee45b6c2SMasami Hiramatsu 8162b394bc4SMasami Hiramatsu ret = init_symbol_maps(user); 817ee45b6c2SMasami Hiramatsu if (ret < 0) 818ee45b6c2SMasami Hiramatsu return ret; 819811dd2aeSMasami Hiramatsu ret = __show_line_range(lr, module, user); 820ee45b6c2SMasami Hiramatsu exit_symbol_maps(); 821ee45b6c2SMasami Hiramatsu 822ee45b6c2SMasami Hiramatsu return ret; 823ee45b6c2SMasami Hiramatsu } 824ee45b6c2SMasami Hiramatsu 825ff741783SMasami Hiramatsu static int show_available_vars_at(struct debuginfo *dinfo, 826ff741783SMasami Hiramatsu struct perf_probe_event *pev, 827ddb2f58fSMasami Hiramatsu struct strfilter *_filter) 828cf6eb489SMasami Hiramatsu { 829cf6eb489SMasami Hiramatsu char *buf; 830bd09d7b5SMasami Hiramatsu int ret, i, nvars; 831cf6eb489SMasami Hiramatsu struct str_node *node; 832cf6eb489SMasami Hiramatsu struct variable_list *vls = NULL, *vl; 8339b118acaSMasami Hiramatsu struct perf_probe_point tmp; 834bd09d7b5SMasami Hiramatsu const char *var; 835cf6eb489SMasami Hiramatsu 836cf6eb489SMasami Hiramatsu buf = synthesize_perf_probe_point(&pev->point); 837cf6eb489SMasami Hiramatsu if (!buf) 838cf6eb489SMasami Hiramatsu return -EINVAL; 839cf6eb489SMasami Hiramatsu pr_debug("Searching variables at %s\n", buf); 840cf6eb489SMasami Hiramatsu 841ddb2f58fSMasami Hiramatsu ret = debuginfo__find_available_vars_at(dinfo, pev, &vls); 8429b118acaSMasami Hiramatsu if (!ret) { /* Not found, retry with an alternative */ 84344225521SMasami Hiramatsu ret = get_alternative_probe_event(dinfo, pev, &tmp); 8449b118acaSMasami Hiramatsu if (!ret) { 8459b118acaSMasami Hiramatsu ret = debuginfo__find_available_vars_at(dinfo, pev, 846ddb2f58fSMasami Hiramatsu &vls); 8479b118acaSMasami Hiramatsu /* Release the old probe_point */ 8489b118acaSMasami Hiramatsu clear_perf_probe_point(&tmp); 8499b118acaSMasami Hiramatsu } 8509b118acaSMasami Hiramatsu } 851bd09d7b5SMasami Hiramatsu if (ret <= 0) { 85269e96eaaSMasami Hiramatsu if (ret == 0 || ret == -ENOENT) { 85369e96eaaSMasami Hiramatsu pr_err("Failed to find the address of %s\n", buf); 85469e96eaaSMasami Hiramatsu ret = -ENOENT; 85569e96eaaSMasami Hiramatsu } else 85669e96eaaSMasami Hiramatsu pr_warning("Debuginfo analysis failed.\n"); 857bd09d7b5SMasami Hiramatsu goto end; 858bd09d7b5SMasami Hiramatsu } 85969e96eaaSMasami Hiramatsu 860bd09d7b5SMasami Hiramatsu /* Some variables are found */ 861cf6eb489SMasami Hiramatsu fprintf(stdout, "Available variables at %s\n", buf); 862cf6eb489SMasami Hiramatsu for (i = 0; i < ret; i++) { 863cf6eb489SMasami Hiramatsu vl = &vls[i]; 864cf6eb489SMasami Hiramatsu /* 865cf6eb489SMasami Hiramatsu * A probe point might be converted to 866cf6eb489SMasami Hiramatsu * several trace points. 867cf6eb489SMasami Hiramatsu */ 868cf6eb489SMasami Hiramatsu fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, 869cf6eb489SMasami Hiramatsu vl->point.offset); 87074cf249dSArnaldo Carvalho de Melo zfree(&vl->point.symbol); 871bd09d7b5SMasami Hiramatsu nvars = 0; 872cf6eb489SMasami Hiramatsu if (vl->vars) { 873bd09d7b5SMasami Hiramatsu strlist__for_each(node, vl->vars) { 874bd09d7b5SMasami Hiramatsu var = strchr(node->s, '\t') + 1; 875bd09d7b5SMasami Hiramatsu if (strfilter__compare(_filter, var)) { 876cf6eb489SMasami Hiramatsu fprintf(stdout, "\t\t%s\n", node->s); 877bd09d7b5SMasami Hiramatsu nvars++; 878bd09d7b5SMasami Hiramatsu } 879bd09d7b5SMasami Hiramatsu } 880cf6eb489SMasami Hiramatsu strlist__delete(vl->vars); 881bd09d7b5SMasami Hiramatsu } 882bd09d7b5SMasami Hiramatsu if (nvars == 0) 883bd09d7b5SMasami Hiramatsu fprintf(stdout, "\t\t(No matched variables)\n"); 884cf6eb489SMasami Hiramatsu } 885cf6eb489SMasami Hiramatsu free(vls); 886bd09d7b5SMasami Hiramatsu end: 887cf6eb489SMasami Hiramatsu free(buf); 888cf6eb489SMasami Hiramatsu return ret; 889cf6eb489SMasami Hiramatsu } 890cf6eb489SMasami Hiramatsu 891cf6eb489SMasami Hiramatsu /* Show available variables on given probe point */ 892cf6eb489SMasami Hiramatsu int show_available_vars(struct perf_probe_event *pevs, int npevs, 893ddb2f58fSMasami Hiramatsu struct strfilter *_filter) 894cf6eb489SMasami Hiramatsu { 895ff741783SMasami Hiramatsu int i, ret = 0; 896ff741783SMasami Hiramatsu struct debuginfo *dinfo; 897cf6eb489SMasami Hiramatsu 8982b394bc4SMasami Hiramatsu ret = init_symbol_maps(pevs->uprobes); 899cf6eb489SMasami Hiramatsu if (ret < 0) 900cf6eb489SMasami Hiramatsu return ret; 901cf6eb489SMasami Hiramatsu 90244225521SMasami Hiramatsu dinfo = open_debuginfo(pevs->target, false); 903ff741783SMasami Hiramatsu if (!dinfo) { 904ee45b6c2SMasami Hiramatsu ret = -ENOENT; 905ee45b6c2SMasami Hiramatsu goto out; 906ff741783SMasami Hiramatsu } 907ff741783SMasami Hiramatsu 908cc446446SMasami Hiramatsu setup_pager(); 909cc446446SMasami Hiramatsu 910ff741783SMasami Hiramatsu for (i = 0; i < npevs && ret >= 0; i++) 911ddb2f58fSMasami Hiramatsu ret = show_available_vars_at(dinfo, &pevs[i], _filter); 912ff741783SMasami Hiramatsu 913ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 914ee45b6c2SMasami Hiramatsu out: 915ee45b6c2SMasami Hiramatsu exit_symbol_maps(); 916cf6eb489SMasami Hiramatsu return ret; 917cf6eb489SMasami Hiramatsu } 918cf6eb489SMasami Hiramatsu 91989fe808aSIngo Molnar #else /* !HAVE_DWARF_SUPPORT */ 9204b4da7f7SMasami Hiramatsu 9215a6f6314SMasami Hiramatsu static int 9225a6f6314SMasami Hiramatsu find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused, 9235a6f6314SMasami Hiramatsu struct perf_probe_point *pp __maybe_unused, 9245a6f6314SMasami Hiramatsu bool is_kprobe __maybe_unused) 9254b4da7f7SMasami Hiramatsu { 9265a6f6314SMasami Hiramatsu return -ENOSYS; 9274b4da7f7SMasami Hiramatsu } 9284b4da7f7SMasami Hiramatsu 9290e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 930ddb2f58fSMasami Hiramatsu struct probe_trace_event **tevs __maybe_unused) 9314b4da7f7SMasami Hiramatsu { 932146a1439SMasami Hiramatsu if (perf_probe_event_need_dwarf(pev)) { 933146a1439SMasami Hiramatsu pr_warning("Debuginfo-analysis is not supported.\n"); 934146a1439SMasami Hiramatsu return -ENOSYS; 935146a1439SMasami Hiramatsu } 936225466f1SSrikar Dronamraju 9374b4da7f7SMasami Hiramatsu return 0; 9384b4da7f7SMasami Hiramatsu } 9394b4da7f7SMasami Hiramatsu 9401d037ca1SIrina Tirdea int show_line_range(struct line_range *lr __maybe_unused, 9412b394bc4SMasami Hiramatsu const char *module __maybe_unused, 9422b394bc4SMasami Hiramatsu bool user __maybe_unused) 9434b4da7f7SMasami Hiramatsu { 944146a1439SMasami Hiramatsu pr_warning("Debuginfo-analysis is not supported.\n"); 945146a1439SMasami Hiramatsu return -ENOSYS; 9464b4da7f7SMasami Hiramatsu } 9474b4da7f7SMasami Hiramatsu 9481d037ca1SIrina Tirdea int show_available_vars(struct perf_probe_event *pevs __maybe_unused, 949ddb2f58fSMasami Hiramatsu int npevs __maybe_unused, 950ddb2f58fSMasami Hiramatsu struct strfilter *filter __maybe_unused) 951cf6eb489SMasami Hiramatsu { 952cf6eb489SMasami Hiramatsu pr_warning("Debuginfo-analysis is not supported.\n"); 953cf6eb489SMasami Hiramatsu return -ENOSYS; 954cf6eb489SMasami Hiramatsu } 955e0faa8d3SMasami Hiramatsu #endif 956e0faa8d3SMasami Hiramatsu 957e53b00d3SMasami Hiramatsu void line_range__clear(struct line_range *lr) 958e53b00d3SMasami Hiramatsu { 959e53b00d3SMasami Hiramatsu free(lr->function); 960e53b00d3SMasami Hiramatsu free(lr->file); 961e53b00d3SMasami Hiramatsu free(lr->path); 962e53b00d3SMasami Hiramatsu free(lr->comp_dir); 9635a62257aSMasami Hiramatsu intlist__delete(lr->line_list); 964e53b00d3SMasami Hiramatsu memset(lr, 0, sizeof(*lr)); 965e53b00d3SMasami Hiramatsu } 966e53b00d3SMasami Hiramatsu 9675a62257aSMasami Hiramatsu int line_range__init(struct line_range *lr) 968e53b00d3SMasami Hiramatsu { 969e53b00d3SMasami Hiramatsu memset(lr, 0, sizeof(*lr)); 9705a62257aSMasami Hiramatsu lr->line_list = intlist__new(NULL); 9715a62257aSMasami Hiramatsu if (!lr->line_list) 9725a62257aSMasami Hiramatsu return -ENOMEM; 9735a62257aSMasami Hiramatsu else 9745a62257aSMasami Hiramatsu return 0; 975e53b00d3SMasami Hiramatsu } 976e53b00d3SMasami Hiramatsu 97721dd9ae5SFranck Bui-Huu static int parse_line_num(char **ptr, int *val, const char *what) 97821dd9ae5SFranck Bui-Huu { 97921dd9ae5SFranck Bui-Huu const char *start = *ptr; 98021dd9ae5SFranck Bui-Huu 98121dd9ae5SFranck Bui-Huu errno = 0; 98221dd9ae5SFranck Bui-Huu *val = strtol(*ptr, ptr, 0); 98321dd9ae5SFranck Bui-Huu if (errno || *ptr == start) { 98421dd9ae5SFranck Bui-Huu semantic_error("'%s' is not a valid number.\n", what); 98521dd9ae5SFranck Bui-Huu return -EINVAL; 98621dd9ae5SFranck Bui-Huu } 98721dd9ae5SFranck Bui-Huu return 0; 98821dd9ae5SFranck Bui-Huu } 98921dd9ae5SFranck Bui-Huu 990573709fdSMasami Hiramatsu /* Check the name is good for event, group or function */ 991573709fdSMasami Hiramatsu static bool is_c_func_name(const char *name) 992573709fdSMasami Hiramatsu { 993573709fdSMasami Hiramatsu if (!isalpha(*name) && *name != '_') 994573709fdSMasami Hiramatsu return false; 995573709fdSMasami Hiramatsu while (*++name != '\0') { 996573709fdSMasami Hiramatsu if (!isalpha(*name) && !isdigit(*name) && *name != '_') 997573709fdSMasami Hiramatsu return false; 998573709fdSMasami Hiramatsu } 999573709fdSMasami Hiramatsu return true; 1000573709fdSMasami Hiramatsu } 1001573709fdSMasami Hiramatsu 10029d95b580SFranck Bui-Huu /* 10039d95b580SFranck Bui-Huu * Stuff 'lr' according to the line range described by 'arg'. 10049d95b580SFranck Bui-Huu * The line range syntax is described by: 10059d95b580SFranck Bui-Huu * 10069d95b580SFranck Bui-Huu * SRC[:SLN[+NUM|-ELN]] 1007e116dfa1SMasami Hiramatsu * FNC[@SRC][:SLN[+NUM|-ELN]] 10089d95b580SFranck Bui-Huu */ 1009146a1439SMasami Hiramatsu int parse_line_range_desc(const char *arg, struct line_range *lr) 1010631c9defSMasami Hiramatsu { 1011e116dfa1SMasami Hiramatsu char *range, *file, *name = strdup(arg); 101221dd9ae5SFranck Bui-Huu int err; 10139d95b580SFranck Bui-Huu 101421dd9ae5SFranck Bui-Huu if (!name) 101521dd9ae5SFranck Bui-Huu return -ENOMEM; 101621dd9ae5SFranck Bui-Huu 101721dd9ae5SFranck Bui-Huu lr->start = 0; 101821dd9ae5SFranck Bui-Huu lr->end = INT_MAX; 101921dd9ae5SFranck Bui-Huu 102021dd9ae5SFranck Bui-Huu range = strchr(name, ':'); 102121dd9ae5SFranck Bui-Huu if (range) { 102221dd9ae5SFranck Bui-Huu *range++ = '\0'; 102321dd9ae5SFranck Bui-Huu 102421dd9ae5SFranck Bui-Huu err = parse_line_num(&range, &lr->start, "start line"); 102521dd9ae5SFranck Bui-Huu if (err) 102621dd9ae5SFranck Bui-Huu goto err; 102721dd9ae5SFranck Bui-Huu 102821dd9ae5SFranck Bui-Huu if (*range == '+' || *range == '-') { 102921dd9ae5SFranck Bui-Huu const char c = *range++; 103021dd9ae5SFranck Bui-Huu 103121dd9ae5SFranck Bui-Huu err = parse_line_num(&range, &lr->end, "end line"); 103221dd9ae5SFranck Bui-Huu if (err) 103321dd9ae5SFranck Bui-Huu goto err; 103421dd9ae5SFranck Bui-Huu 103521dd9ae5SFranck Bui-Huu if (c == '+') { 103621dd9ae5SFranck Bui-Huu lr->end += lr->start; 103721dd9ae5SFranck Bui-Huu /* 1038dda4ab34SMasami Hiramatsu * Adjust the number of lines here. 1039dda4ab34SMasami Hiramatsu * If the number of lines == 1, the 1040dda4ab34SMasami Hiramatsu * the end of line should be equal to 1041dda4ab34SMasami Hiramatsu * the start of line. 1042dda4ab34SMasami Hiramatsu */ 104321dd9ae5SFranck Bui-Huu lr->end--; 104421dd9ae5SFranck Bui-Huu } 104521dd9ae5SFranck Bui-Huu } 104621dd9ae5SFranck Bui-Huu 1047d3b63d7aSMasami Hiramatsu pr_debug("Line range is %d to %d\n", lr->start, lr->end); 104821dd9ae5SFranck Bui-Huu 104921dd9ae5SFranck Bui-Huu err = -EINVAL; 1050d3b63d7aSMasami Hiramatsu if (lr->start > lr->end) { 1051631c9defSMasami Hiramatsu semantic_error("Start line must be smaller" 1052146a1439SMasami Hiramatsu " than end line.\n"); 105321dd9ae5SFranck Bui-Huu goto err; 1054146a1439SMasami Hiramatsu } 105521dd9ae5SFranck Bui-Huu if (*range != '\0') { 105621dd9ae5SFranck Bui-Huu semantic_error("Tailing with invalid str '%s'.\n", range); 105721dd9ae5SFranck Bui-Huu goto err; 1058146a1439SMasami Hiramatsu } 1059d3b63d7aSMasami Hiramatsu } 106002b95dadSMasami Hiramatsu 1061e116dfa1SMasami Hiramatsu file = strchr(name, '@'); 1062e116dfa1SMasami Hiramatsu if (file) { 1063e116dfa1SMasami Hiramatsu *file = '\0'; 1064e116dfa1SMasami Hiramatsu lr->file = strdup(++file); 1065e116dfa1SMasami Hiramatsu if (lr->file == NULL) { 1066e116dfa1SMasami Hiramatsu err = -ENOMEM; 1067e116dfa1SMasami Hiramatsu goto err; 1068e116dfa1SMasami Hiramatsu } 1069e116dfa1SMasami Hiramatsu lr->function = name; 1070573709fdSMasami Hiramatsu } else if (strchr(name, '/') || strchr(name, '.')) 107121dd9ae5SFranck Bui-Huu lr->file = name; 1072573709fdSMasami Hiramatsu else if (is_c_func_name(name))/* We reuse it for checking funcname */ 107321dd9ae5SFranck Bui-Huu lr->function = name; 1074573709fdSMasami Hiramatsu else { /* Invalid name */ 1075573709fdSMasami Hiramatsu semantic_error("'%s' is not a valid function name.\n", name); 1076573709fdSMasami Hiramatsu err = -EINVAL; 1077573709fdSMasami Hiramatsu goto err; 1078573709fdSMasami Hiramatsu } 1079146a1439SMasami Hiramatsu 1080146a1439SMasami Hiramatsu return 0; 108121dd9ae5SFranck Bui-Huu err: 108221dd9ae5SFranck Bui-Huu free(name); 108321dd9ae5SFranck Bui-Huu return err; 1084631c9defSMasami Hiramatsu } 1085631c9defSMasami Hiramatsu 108650656eecSMasami Hiramatsu /* Parse probepoint definition. */ 1087146a1439SMasami Hiramatsu static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) 108850656eecSMasami Hiramatsu { 10894235b045SMasami Hiramatsu struct perf_probe_point *pp = &pev->point; 109050656eecSMasami Hiramatsu char *ptr, *tmp; 109150656eecSMasami Hiramatsu char c, nc = 0; 10923099c026SNaveen N. Rao bool file_spec = false; 109350656eecSMasami Hiramatsu /* 109450656eecSMasami Hiramatsu * <Syntax> 10952a9c8c36SMasami Hiramatsu * perf probe [EVENT=]SRC[:LN|;PTN] 10962a9c8c36SMasami Hiramatsu * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] 1097af663d75SMasami Hiramatsu * 1098af663d75SMasami Hiramatsu * TODO:Group name support 109950656eecSMasami Hiramatsu */ 1100e59d29e8SWang Nan if (!arg) 1101e59d29e8SWang Nan return -EINVAL; 110250656eecSMasami Hiramatsu 11032a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";=@+%"); 11042a9c8c36SMasami Hiramatsu if (ptr && *ptr == '=') { /* Event name */ 1105af663d75SMasami Hiramatsu *ptr = '\0'; 1106af663d75SMasami Hiramatsu tmp = ptr + 1; 1107146a1439SMasami Hiramatsu if (strchr(arg, ':')) { 1108146a1439SMasami Hiramatsu semantic_error("Group name is not supported yet.\n"); 1109146a1439SMasami Hiramatsu return -ENOTSUP; 1110146a1439SMasami Hiramatsu } 1111573709fdSMasami Hiramatsu if (!is_c_func_name(arg)) { 1112b7702a21SMasami Hiramatsu semantic_error("%s is bad for event name -it must " 1113146a1439SMasami Hiramatsu "follow C symbol-naming rule.\n", arg); 1114146a1439SMasami Hiramatsu return -EINVAL; 1115146a1439SMasami Hiramatsu } 111602b95dadSMasami Hiramatsu pev->event = strdup(arg); 111702b95dadSMasami Hiramatsu if (pev->event == NULL) 111802b95dadSMasami Hiramatsu return -ENOMEM; 11194235b045SMasami Hiramatsu pev->group = NULL; 1120af663d75SMasami Hiramatsu arg = tmp; 1121af663d75SMasami Hiramatsu } 1122af663d75SMasami Hiramatsu 11233099c026SNaveen N. Rao /* 11243099c026SNaveen N. Rao * Check arg is function or file name and copy it. 11253099c026SNaveen N. Rao * 11263099c026SNaveen N. Rao * We consider arg to be a file spec if and only if it satisfies 11273099c026SNaveen N. Rao * all of the below criteria:: 11283099c026SNaveen N. Rao * - it does not include any of "+@%", 11293099c026SNaveen N. Rao * - it includes one of ":;", and 11303099c026SNaveen N. Rao * - it has a period '.' in the name. 11313099c026SNaveen N. Rao * 11323099c026SNaveen N. Rao * Otherwise, we consider arg to be a function specification. 11333099c026SNaveen N. Rao */ 11343099c026SNaveen N. Rao if (!strpbrk(arg, "+@%") && (ptr = strpbrk(arg, ";:")) != NULL) { 11353099c026SNaveen N. Rao /* This is a file spec if it includes a '.' before ; or : */ 11363099c026SNaveen N. Rao if (memchr(arg, '.', ptr - arg)) 11373099c026SNaveen N. Rao file_spec = true; 11383099c026SNaveen N. Rao } 11393099c026SNaveen N. Rao 11402a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";:+@%"); 114150656eecSMasami Hiramatsu if (ptr) { 114250656eecSMasami Hiramatsu nc = *ptr; 114350656eecSMasami Hiramatsu *ptr++ = '\0'; 114450656eecSMasami Hiramatsu } 114550656eecSMasami Hiramatsu 114602b95dadSMasami Hiramatsu tmp = strdup(arg); 114702b95dadSMasami Hiramatsu if (tmp == NULL) 114802b95dadSMasami Hiramatsu return -ENOMEM; 114902b95dadSMasami Hiramatsu 11503099c026SNaveen N. Rao if (file_spec) 115102b95dadSMasami Hiramatsu pp->file = tmp; 11523099c026SNaveen N. Rao else 115302b95dadSMasami Hiramatsu pp->function = tmp; 115450656eecSMasami Hiramatsu 115550656eecSMasami Hiramatsu /* Parse other options */ 115650656eecSMasami Hiramatsu while (ptr) { 115750656eecSMasami Hiramatsu arg = ptr; 115850656eecSMasami Hiramatsu c = nc; 11592a9c8c36SMasami Hiramatsu if (c == ';') { /* Lazy pattern must be the last part */ 116002b95dadSMasami Hiramatsu pp->lazy_line = strdup(arg); 116102b95dadSMasami Hiramatsu if (pp->lazy_line == NULL) 116202b95dadSMasami Hiramatsu return -ENOMEM; 11632a9c8c36SMasami Hiramatsu break; 11642a9c8c36SMasami Hiramatsu } 11652a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";:+@%"); 116650656eecSMasami Hiramatsu if (ptr) { 116750656eecSMasami Hiramatsu nc = *ptr; 116850656eecSMasami Hiramatsu *ptr++ = '\0'; 116950656eecSMasami Hiramatsu } 117050656eecSMasami Hiramatsu switch (c) { 117150656eecSMasami Hiramatsu case ':': /* Line number */ 117250656eecSMasami Hiramatsu pp->line = strtoul(arg, &tmp, 0); 1173146a1439SMasami Hiramatsu if (*tmp != '\0') { 11742a9c8c36SMasami Hiramatsu semantic_error("There is non-digit char" 1175146a1439SMasami Hiramatsu " in line number.\n"); 1176146a1439SMasami Hiramatsu return -EINVAL; 1177146a1439SMasami Hiramatsu } 117850656eecSMasami Hiramatsu break; 117950656eecSMasami Hiramatsu case '+': /* Byte offset from a symbol */ 118050656eecSMasami Hiramatsu pp->offset = strtoul(arg, &tmp, 0); 1181146a1439SMasami Hiramatsu if (*tmp != '\0') { 11822a9c8c36SMasami Hiramatsu semantic_error("There is non-digit character" 1183146a1439SMasami Hiramatsu " in offset.\n"); 1184146a1439SMasami Hiramatsu return -EINVAL; 1185146a1439SMasami Hiramatsu } 118650656eecSMasami Hiramatsu break; 118750656eecSMasami Hiramatsu case '@': /* File name */ 1188146a1439SMasami Hiramatsu if (pp->file) { 1189146a1439SMasami Hiramatsu semantic_error("SRC@SRC is not allowed.\n"); 1190146a1439SMasami Hiramatsu return -EINVAL; 1191146a1439SMasami Hiramatsu } 119202b95dadSMasami Hiramatsu pp->file = strdup(arg); 119302b95dadSMasami Hiramatsu if (pp->file == NULL) 119402b95dadSMasami Hiramatsu return -ENOMEM; 119550656eecSMasami Hiramatsu break; 119650656eecSMasami Hiramatsu case '%': /* Probe places */ 119750656eecSMasami Hiramatsu if (strcmp(arg, "return") == 0) { 119850656eecSMasami Hiramatsu pp->retprobe = 1; 1199146a1439SMasami Hiramatsu } else { /* Others not supported yet */ 1200146a1439SMasami Hiramatsu semantic_error("%%%s is not supported.\n", arg); 1201146a1439SMasami Hiramatsu return -ENOTSUP; 1202146a1439SMasami Hiramatsu } 120350656eecSMasami Hiramatsu break; 1204146a1439SMasami Hiramatsu default: /* Buggy case */ 1205146a1439SMasami Hiramatsu pr_err("This program has a bug at %s:%d.\n", 1206146a1439SMasami Hiramatsu __FILE__, __LINE__); 1207146a1439SMasami Hiramatsu return -ENOTSUP; 120850656eecSMasami Hiramatsu break; 120950656eecSMasami Hiramatsu } 121050656eecSMasami Hiramatsu } 121150656eecSMasami Hiramatsu 121250656eecSMasami Hiramatsu /* Exclusion check */ 1213146a1439SMasami Hiramatsu if (pp->lazy_line && pp->line) { 12140e43e5d2SMasami Hiramatsu semantic_error("Lazy pattern can't be used with" 12150e43e5d2SMasami Hiramatsu " line number.\n"); 1216146a1439SMasami Hiramatsu return -EINVAL; 1217146a1439SMasami Hiramatsu } 12182a9c8c36SMasami Hiramatsu 1219146a1439SMasami Hiramatsu if (pp->lazy_line && pp->offset) { 12200e43e5d2SMasami Hiramatsu semantic_error("Lazy pattern can't be used with offset.\n"); 1221146a1439SMasami Hiramatsu return -EINVAL; 1222146a1439SMasami Hiramatsu } 12232a9c8c36SMasami Hiramatsu 1224146a1439SMasami Hiramatsu if (pp->line && pp->offset) { 12250e43e5d2SMasami Hiramatsu semantic_error("Offset can't be used with line number.\n"); 1226146a1439SMasami Hiramatsu return -EINVAL; 1227146a1439SMasami Hiramatsu } 122850656eecSMasami Hiramatsu 1229146a1439SMasami Hiramatsu if (!pp->line && !pp->lazy_line && pp->file && !pp->function) { 12302a9c8c36SMasami Hiramatsu semantic_error("File always requires line number or " 12310e43e5d2SMasami Hiramatsu "lazy pattern.\n"); 1232146a1439SMasami Hiramatsu return -EINVAL; 1233146a1439SMasami Hiramatsu } 123450656eecSMasami Hiramatsu 1235146a1439SMasami Hiramatsu if (pp->offset && !pp->function) { 12360e43e5d2SMasami Hiramatsu semantic_error("Offset requires an entry function.\n"); 1237146a1439SMasami Hiramatsu return -EINVAL; 1238146a1439SMasami Hiramatsu } 123950656eecSMasami Hiramatsu 1240146a1439SMasami Hiramatsu if (pp->retprobe && !pp->function) { 12410e43e5d2SMasami Hiramatsu semantic_error("Return probe requires an entry function.\n"); 1242146a1439SMasami Hiramatsu return -EINVAL; 1243146a1439SMasami Hiramatsu } 124450656eecSMasami Hiramatsu 1245146a1439SMasami Hiramatsu if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { 12462a9c8c36SMasami Hiramatsu semantic_error("Offset/Line/Lazy pattern can't be used with " 12470e43e5d2SMasami Hiramatsu "return probe.\n"); 1248146a1439SMasami Hiramatsu return -EINVAL; 1249146a1439SMasami Hiramatsu } 125050656eecSMasami Hiramatsu 12514235b045SMasami Hiramatsu pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n", 12522a9c8c36SMasami Hiramatsu pp->function, pp->file, pp->line, pp->offset, pp->retprobe, 12532a9c8c36SMasami Hiramatsu pp->lazy_line); 1254146a1439SMasami Hiramatsu return 0; 125550656eecSMasami Hiramatsu } 125650656eecSMasami Hiramatsu 12577df2f329SMasami Hiramatsu /* Parse perf-probe event argument */ 1258146a1439SMasami Hiramatsu static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) 12597df2f329SMasami Hiramatsu { 1260b2a3c12bSMasami Hiramatsu char *tmp, *goodname; 12617df2f329SMasami Hiramatsu struct perf_probe_arg_field **fieldp; 12627df2f329SMasami Hiramatsu 12637df2f329SMasami Hiramatsu pr_debug("parsing arg: %s into ", str); 12647df2f329SMasami Hiramatsu 126548481938SMasami Hiramatsu tmp = strchr(str, '='); 126648481938SMasami Hiramatsu if (tmp) { 126702b95dadSMasami Hiramatsu arg->name = strndup(str, tmp - str); 126802b95dadSMasami Hiramatsu if (arg->name == NULL) 126902b95dadSMasami Hiramatsu return -ENOMEM; 127011a1ca35SMasami Hiramatsu pr_debug("name:%s ", arg->name); 127148481938SMasami Hiramatsu str = tmp + 1; 127248481938SMasami Hiramatsu } 127348481938SMasami Hiramatsu 127411a1ca35SMasami Hiramatsu tmp = strchr(str, ':'); 127511a1ca35SMasami Hiramatsu if (tmp) { /* Type setting */ 127611a1ca35SMasami Hiramatsu *tmp = '\0'; 127702b95dadSMasami Hiramatsu arg->type = strdup(tmp + 1); 127802b95dadSMasami Hiramatsu if (arg->type == NULL) 127902b95dadSMasami Hiramatsu return -ENOMEM; 128011a1ca35SMasami Hiramatsu pr_debug("type:%s ", arg->type); 128111a1ca35SMasami Hiramatsu } 128211a1ca35SMasami Hiramatsu 1283b2a3c12bSMasami Hiramatsu tmp = strpbrk(str, "-.["); 12847df2f329SMasami Hiramatsu if (!is_c_varname(str) || !tmp) { 12857df2f329SMasami Hiramatsu /* A variable, register, symbol or special value */ 128602b95dadSMasami Hiramatsu arg->var = strdup(str); 128702b95dadSMasami Hiramatsu if (arg->var == NULL) 128802b95dadSMasami Hiramatsu return -ENOMEM; 128948481938SMasami Hiramatsu pr_debug("%s\n", arg->var); 1290146a1439SMasami Hiramatsu return 0; 12917df2f329SMasami Hiramatsu } 12927df2f329SMasami Hiramatsu 1293b2a3c12bSMasami Hiramatsu /* Structure fields or array element */ 129402b95dadSMasami Hiramatsu arg->var = strndup(str, tmp - str); 129502b95dadSMasami Hiramatsu if (arg->var == NULL) 129602b95dadSMasami Hiramatsu return -ENOMEM; 1297b2a3c12bSMasami Hiramatsu goodname = arg->var; 129848481938SMasami Hiramatsu pr_debug("%s, ", arg->var); 12997df2f329SMasami Hiramatsu fieldp = &arg->field; 13007df2f329SMasami Hiramatsu 13017df2f329SMasami Hiramatsu do { 1302e334016fSMasami Hiramatsu *fieldp = zalloc(sizeof(struct perf_probe_arg_field)); 1303e334016fSMasami Hiramatsu if (*fieldp == NULL) 1304e334016fSMasami Hiramatsu return -ENOMEM; 1305b2a3c12bSMasami Hiramatsu if (*tmp == '[') { /* Array */ 1306b2a3c12bSMasami Hiramatsu str = tmp; 1307b2a3c12bSMasami Hiramatsu (*fieldp)->index = strtol(str + 1, &tmp, 0); 1308b2a3c12bSMasami Hiramatsu (*fieldp)->ref = true; 1309b2a3c12bSMasami Hiramatsu if (*tmp != ']' || tmp == str + 1) { 1310b2a3c12bSMasami Hiramatsu semantic_error("Array index must be a" 1311b2a3c12bSMasami Hiramatsu " number.\n"); 1312b2a3c12bSMasami Hiramatsu return -EINVAL; 1313b2a3c12bSMasami Hiramatsu } 1314b2a3c12bSMasami Hiramatsu tmp++; 1315b2a3c12bSMasami Hiramatsu if (*tmp == '\0') 1316b2a3c12bSMasami Hiramatsu tmp = NULL; 1317b2a3c12bSMasami Hiramatsu } else { /* Structure */ 13187df2f329SMasami Hiramatsu if (*tmp == '.') { 13197df2f329SMasami Hiramatsu str = tmp + 1; 13207df2f329SMasami Hiramatsu (*fieldp)->ref = false; 13217df2f329SMasami Hiramatsu } else if (tmp[1] == '>') { 13227df2f329SMasami Hiramatsu str = tmp + 2; 13237df2f329SMasami Hiramatsu (*fieldp)->ref = true; 1324146a1439SMasami Hiramatsu } else { 1325b2a3c12bSMasami Hiramatsu semantic_error("Argument parse error: %s\n", 1326b2a3c12bSMasami Hiramatsu str); 1327146a1439SMasami Hiramatsu return -EINVAL; 1328146a1439SMasami Hiramatsu } 1329b2a3c12bSMasami Hiramatsu tmp = strpbrk(str, "-.["); 1330b2a3c12bSMasami Hiramatsu } 13317df2f329SMasami Hiramatsu if (tmp) { 133202b95dadSMasami Hiramatsu (*fieldp)->name = strndup(str, tmp - str); 133302b95dadSMasami Hiramatsu if ((*fieldp)->name == NULL) 133402b95dadSMasami Hiramatsu return -ENOMEM; 1335b2a3c12bSMasami Hiramatsu if (*str != '[') 1336b2a3c12bSMasami Hiramatsu goodname = (*fieldp)->name; 13377df2f329SMasami Hiramatsu pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); 13387df2f329SMasami Hiramatsu fieldp = &(*fieldp)->next; 13397df2f329SMasami Hiramatsu } 13407df2f329SMasami Hiramatsu } while (tmp); 134102b95dadSMasami Hiramatsu (*fieldp)->name = strdup(str); 134202b95dadSMasami Hiramatsu if ((*fieldp)->name == NULL) 134302b95dadSMasami Hiramatsu return -ENOMEM; 1344b2a3c12bSMasami Hiramatsu if (*str != '[') 1345b2a3c12bSMasami Hiramatsu goodname = (*fieldp)->name; 13467df2f329SMasami Hiramatsu pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); 1347df0faf4bSMasami Hiramatsu 1348b2a3c12bSMasami Hiramatsu /* If no name is specified, set the last field name (not array index)*/ 134902b95dadSMasami Hiramatsu if (!arg->name) { 1350b2a3c12bSMasami Hiramatsu arg->name = strdup(goodname); 135102b95dadSMasami Hiramatsu if (arg->name == NULL) 135202b95dadSMasami Hiramatsu return -ENOMEM; 135302b95dadSMasami Hiramatsu } 1354146a1439SMasami Hiramatsu return 0; 13557df2f329SMasami Hiramatsu } 13567df2f329SMasami Hiramatsu 13574235b045SMasami Hiramatsu /* Parse perf-probe event command */ 1358146a1439SMasami Hiramatsu int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) 135950656eecSMasami Hiramatsu { 1360e1c01d61SMasami Hiramatsu char **argv; 1361146a1439SMasami Hiramatsu int argc, i, ret = 0; 1362fac13fd5SMasami Hiramatsu 13634235b045SMasami Hiramatsu argv = argv_split(cmd, &argc); 1364146a1439SMasami Hiramatsu if (!argv) { 1365146a1439SMasami Hiramatsu pr_debug("Failed to split arguments.\n"); 1366146a1439SMasami Hiramatsu return -ENOMEM; 1367146a1439SMasami Hiramatsu } 1368146a1439SMasami Hiramatsu if (argc - 1 > MAX_PROBE_ARGS) { 1369146a1439SMasami Hiramatsu semantic_error("Too many probe arguments (%d).\n", argc - 1); 1370146a1439SMasami Hiramatsu ret = -ERANGE; 1371146a1439SMasami Hiramatsu goto out; 1372146a1439SMasami Hiramatsu } 137350656eecSMasami Hiramatsu /* Parse probe point */ 1374146a1439SMasami Hiramatsu ret = parse_perf_probe_point(argv[0], pev); 1375146a1439SMasami Hiramatsu if (ret < 0) 1376146a1439SMasami Hiramatsu goto out; 137750656eecSMasami Hiramatsu 1378e1c01d61SMasami Hiramatsu /* Copy arguments and ensure return probe has no C argument */ 13794235b045SMasami Hiramatsu pev->nargs = argc - 1; 1380e334016fSMasami Hiramatsu pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); 1381e334016fSMasami Hiramatsu if (pev->args == NULL) { 1382e334016fSMasami Hiramatsu ret = -ENOMEM; 1383e334016fSMasami Hiramatsu goto out; 1384e334016fSMasami Hiramatsu } 1385146a1439SMasami Hiramatsu for (i = 0; i < pev->nargs && ret >= 0; i++) { 1386146a1439SMasami Hiramatsu ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]); 1387146a1439SMasami Hiramatsu if (ret >= 0 && 1388146a1439SMasami Hiramatsu is_c_varname(pev->args[i].var) && pev->point.retprobe) { 13894235b045SMasami Hiramatsu semantic_error("You can't specify local variable for" 1390146a1439SMasami Hiramatsu " kretprobe.\n"); 1391146a1439SMasami Hiramatsu ret = -EINVAL; 1392e1c01d61SMasami Hiramatsu } 1393146a1439SMasami Hiramatsu } 1394146a1439SMasami Hiramatsu out: 1395e1c01d61SMasami Hiramatsu argv_free(argv); 1396146a1439SMasami Hiramatsu 1397146a1439SMasami Hiramatsu return ret; 139850656eecSMasami Hiramatsu } 139950656eecSMasami Hiramatsu 14004235b045SMasami Hiramatsu /* Return true if this perf_probe_event requires debuginfo */ 14014235b045SMasami Hiramatsu bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) 14024de189feSMasami Hiramatsu { 14034235b045SMasami Hiramatsu int i; 14044235b045SMasami Hiramatsu 14054235b045SMasami Hiramatsu if (pev->point.file || pev->point.line || pev->point.lazy_line) 14064235b045SMasami Hiramatsu return true; 14074235b045SMasami Hiramatsu 14084235b045SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) 140948481938SMasami Hiramatsu if (is_c_varname(pev->args[i].var)) 14104235b045SMasami Hiramatsu return true; 14114235b045SMasami Hiramatsu 14124235b045SMasami Hiramatsu return false; 14134235b045SMasami Hiramatsu } 14144235b045SMasami Hiramatsu 14150e60836bSSrikar Dronamraju /* Parse probe_events event into struct probe_point */ 14160e60836bSSrikar Dronamraju static int parse_probe_trace_command(const char *cmd, 14170e60836bSSrikar Dronamraju struct probe_trace_event *tev) 14184235b045SMasami Hiramatsu { 14190e60836bSSrikar Dronamraju struct probe_trace_point *tp = &tev->point; 14204de189feSMasami Hiramatsu char pr; 14214de189feSMasami Hiramatsu char *p; 1422bcbd0040SIrina Tirdea char *argv0_str = NULL, *fmt, *fmt1_str, *fmt2_str, *fmt3_str; 14234de189feSMasami Hiramatsu int ret, i, argc; 14244de189feSMasami Hiramatsu char **argv; 14254de189feSMasami Hiramatsu 14260e60836bSSrikar Dronamraju pr_debug("Parsing probe_events: %s\n", cmd); 14274235b045SMasami Hiramatsu argv = argv_split(cmd, &argc); 1428146a1439SMasami Hiramatsu if (!argv) { 1429146a1439SMasami Hiramatsu pr_debug("Failed to split arguments.\n"); 1430146a1439SMasami Hiramatsu return -ENOMEM; 1431146a1439SMasami Hiramatsu } 1432146a1439SMasami Hiramatsu if (argc < 2) { 1433146a1439SMasami Hiramatsu semantic_error("Too few probe arguments.\n"); 1434146a1439SMasami Hiramatsu ret = -ERANGE; 1435146a1439SMasami Hiramatsu goto out; 1436146a1439SMasami Hiramatsu } 14374de189feSMasami Hiramatsu 14384de189feSMasami Hiramatsu /* Scan event and group name. */ 1439bcbd0040SIrina Tirdea argv0_str = strdup(argv[0]); 1440bcbd0040SIrina Tirdea if (argv0_str == NULL) { 1441bcbd0040SIrina Tirdea ret = -ENOMEM; 1442bcbd0040SIrina Tirdea goto out; 1443bcbd0040SIrina Tirdea } 1444bcbd0040SIrina Tirdea fmt1_str = strtok_r(argv0_str, ":", &fmt); 1445bcbd0040SIrina Tirdea fmt2_str = strtok_r(NULL, "/", &fmt); 1446bcbd0040SIrina Tirdea fmt3_str = strtok_r(NULL, " \t", &fmt); 1447bcbd0040SIrina Tirdea if (fmt1_str == NULL || strlen(fmt1_str) != 1 || fmt2_str == NULL 1448bcbd0040SIrina Tirdea || fmt3_str == NULL) { 1449146a1439SMasami Hiramatsu semantic_error("Failed to parse event name: %s\n", argv[0]); 1450146a1439SMasami Hiramatsu ret = -EINVAL; 1451146a1439SMasami Hiramatsu goto out; 1452146a1439SMasami Hiramatsu } 1453bcbd0040SIrina Tirdea pr = fmt1_str[0]; 1454bcbd0040SIrina Tirdea tev->group = strdup(fmt2_str); 1455bcbd0040SIrina Tirdea tev->event = strdup(fmt3_str); 1456bcbd0040SIrina Tirdea if (tev->group == NULL || tev->event == NULL) { 1457bcbd0040SIrina Tirdea ret = -ENOMEM; 1458bcbd0040SIrina Tirdea goto out; 1459bcbd0040SIrina Tirdea } 14604235b045SMasami Hiramatsu pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr); 14614de189feSMasami Hiramatsu 14624235b045SMasami Hiramatsu tp->retprobe = (pr == 'r'); 14634de189feSMasami Hiramatsu 1464190b57fcSMasami Hiramatsu /* Scan module name(if there), function name and offset */ 1465190b57fcSMasami Hiramatsu p = strchr(argv[1], ':'); 1466190b57fcSMasami Hiramatsu if (p) { 1467190b57fcSMasami Hiramatsu tp->module = strndup(argv[1], p - argv[1]); 1468190b57fcSMasami Hiramatsu p++; 1469190b57fcSMasami Hiramatsu } else 1470190b57fcSMasami Hiramatsu p = argv[1]; 1471bcbd0040SIrina Tirdea fmt1_str = strtok_r(p, "+", &fmt); 14725a6f6314SMasami Hiramatsu if (fmt1_str[0] == '0') /* only the address started with 0x */ 14735a6f6314SMasami Hiramatsu tp->address = strtoul(fmt1_str, NULL, 0); 14745a6f6314SMasami Hiramatsu else { 14755a6f6314SMasami Hiramatsu /* Only the symbol-based probe has offset */ 1476bcbd0040SIrina Tirdea tp->symbol = strdup(fmt1_str); 1477bcbd0040SIrina Tirdea if (tp->symbol == NULL) { 1478bcbd0040SIrina Tirdea ret = -ENOMEM; 1479bcbd0040SIrina Tirdea goto out; 1480bcbd0040SIrina Tirdea } 1481bcbd0040SIrina Tirdea fmt2_str = strtok_r(NULL, "", &fmt); 1482bcbd0040SIrina Tirdea if (fmt2_str == NULL) 14834235b045SMasami Hiramatsu tp->offset = 0; 1484bcbd0040SIrina Tirdea else 1485bcbd0040SIrina Tirdea tp->offset = strtoul(fmt2_str, NULL, 10); 14865a6f6314SMasami Hiramatsu } 14874de189feSMasami Hiramatsu 14884235b045SMasami Hiramatsu tev->nargs = argc - 2; 14890e60836bSSrikar Dronamraju tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1490e334016fSMasami Hiramatsu if (tev->args == NULL) { 1491e334016fSMasami Hiramatsu ret = -ENOMEM; 1492e334016fSMasami Hiramatsu goto out; 1493e334016fSMasami Hiramatsu } 14944235b045SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 14954de189feSMasami Hiramatsu p = strchr(argv[i + 2], '='); 14964de189feSMasami Hiramatsu if (p) /* We don't need which register is assigned. */ 14974235b045SMasami Hiramatsu *p++ = '\0'; 14984235b045SMasami Hiramatsu else 14994235b045SMasami Hiramatsu p = argv[i + 2]; 150002b95dadSMasami Hiramatsu tev->args[i].name = strdup(argv[i + 2]); 15014235b045SMasami Hiramatsu /* TODO: parse regs and offset */ 150202b95dadSMasami Hiramatsu tev->args[i].value = strdup(p); 150302b95dadSMasami Hiramatsu if (tev->args[i].name == NULL || tev->args[i].value == NULL) { 150402b95dadSMasami Hiramatsu ret = -ENOMEM; 150502b95dadSMasami Hiramatsu goto out; 150602b95dadSMasami Hiramatsu } 15074de189feSMasami Hiramatsu } 1508146a1439SMasami Hiramatsu ret = 0; 1509146a1439SMasami Hiramatsu out: 1510bcbd0040SIrina Tirdea free(argv0_str); 15114de189feSMasami Hiramatsu argv_free(argv); 1512146a1439SMasami Hiramatsu return ret; 15134de189feSMasami Hiramatsu } 15144de189feSMasami Hiramatsu 15157df2f329SMasami Hiramatsu /* Compose only probe arg */ 15167df2f329SMasami Hiramatsu int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) 15177df2f329SMasami Hiramatsu { 15187df2f329SMasami Hiramatsu struct perf_probe_arg_field *field = pa->field; 15197df2f329SMasami Hiramatsu int ret; 15207df2f329SMasami Hiramatsu char *tmp = buf; 15217df2f329SMasami Hiramatsu 152248481938SMasami Hiramatsu if (pa->name && pa->var) 152348481938SMasami Hiramatsu ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var); 152448481938SMasami Hiramatsu else 152548481938SMasami Hiramatsu ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var); 15267df2f329SMasami Hiramatsu if (ret <= 0) 15277df2f329SMasami Hiramatsu goto error; 15287df2f329SMasami Hiramatsu tmp += ret; 15297df2f329SMasami Hiramatsu len -= ret; 15307df2f329SMasami Hiramatsu 15317df2f329SMasami Hiramatsu while (field) { 1532b2a3c12bSMasami Hiramatsu if (field->name[0] == '[') 1533b2a3c12bSMasami Hiramatsu ret = e_snprintf(tmp, len, "%s", field->name); 1534b2a3c12bSMasami Hiramatsu else 1535b2a3c12bSMasami Hiramatsu ret = e_snprintf(tmp, len, "%s%s", 1536b2a3c12bSMasami Hiramatsu field->ref ? "->" : ".", field->name); 15377df2f329SMasami Hiramatsu if (ret <= 0) 15387df2f329SMasami Hiramatsu goto error; 15397df2f329SMasami Hiramatsu tmp += ret; 15407df2f329SMasami Hiramatsu len -= ret; 15417df2f329SMasami Hiramatsu field = field->next; 15427df2f329SMasami Hiramatsu } 154311a1ca35SMasami Hiramatsu 154411a1ca35SMasami Hiramatsu if (pa->type) { 154511a1ca35SMasami Hiramatsu ret = e_snprintf(tmp, len, ":%s", pa->type); 154611a1ca35SMasami Hiramatsu if (ret <= 0) 154711a1ca35SMasami Hiramatsu goto error; 154811a1ca35SMasami Hiramatsu tmp += ret; 154911a1ca35SMasami Hiramatsu len -= ret; 155011a1ca35SMasami Hiramatsu } 155111a1ca35SMasami Hiramatsu 15527df2f329SMasami Hiramatsu return tmp - buf; 15537df2f329SMasami Hiramatsu error: 15545f03cba4SMasami Hiramatsu pr_debug("Failed to synthesize perf probe argument: %d\n", ret); 1555146a1439SMasami Hiramatsu return ret; 15567df2f329SMasami Hiramatsu } 15577df2f329SMasami Hiramatsu 15584235b045SMasami Hiramatsu /* Compose only probe point (not argument) */ 15594235b045SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp) 156050656eecSMasami Hiramatsu { 1561fb1587d8SMasami Hiramatsu char *buf, *tmp; 1562fb1587d8SMasami Hiramatsu char offs[32] = "", line[32] = "", file[32] = ""; 1563fb1587d8SMasami Hiramatsu int ret, len; 156450656eecSMasami Hiramatsu 1565e334016fSMasami Hiramatsu buf = zalloc(MAX_CMDLEN); 1566e334016fSMasami Hiramatsu if (buf == NULL) { 1567e334016fSMasami Hiramatsu ret = -ENOMEM; 1568e334016fSMasami Hiramatsu goto error; 1569e334016fSMasami Hiramatsu } 15704de189feSMasami Hiramatsu if (pp->offset) { 1571fb1587d8SMasami Hiramatsu ret = e_snprintf(offs, 32, "+%lu", pp->offset); 15724de189feSMasami Hiramatsu if (ret <= 0) 15734de189feSMasami Hiramatsu goto error; 15744de189feSMasami Hiramatsu } 15754de189feSMasami Hiramatsu if (pp->line) { 1576fb1587d8SMasami Hiramatsu ret = e_snprintf(line, 32, ":%d", pp->line); 1577fb1587d8SMasami Hiramatsu if (ret <= 0) 1578fb1587d8SMasami Hiramatsu goto error; 1579fb1587d8SMasami Hiramatsu } 1580fb1587d8SMasami Hiramatsu if (pp->file) { 158132ae2adeSFranck Bui-Huu tmp = pp->file; 158232ae2adeSFranck Bui-Huu len = strlen(tmp); 158332ae2adeSFranck Bui-Huu if (len > 30) { 158432ae2adeSFranck Bui-Huu tmp = strchr(pp->file + len - 30, '/'); 158532ae2adeSFranck Bui-Huu tmp = tmp ? tmp + 1 : pp->file + len - 30; 158632ae2adeSFranck Bui-Huu } 158732ae2adeSFranck Bui-Huu ret = e_snprintf(file, 32, "@%s", tmp); 15884de189feSMasami Hiramatsu if (ret <= 0) 15894de189feSMasami Hiramatsu goto error; 15904de189feSMasami Hiramatsu } 15914de189feSMasami Hiramatsu 15924de189feSMasami Hiramatsu if (pp->function) 1593fb1587d8SMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function, 1594fb1587d8SMasami Hiramatsu offs, pp->retprobe ? "%return" : "", line, 1595fb1587d8SMasami Hiramatsu file); 15964de189feSMasami Hiramatsu else 1597fb1587d8SMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line); 15984235b045SMasami Hiramatsu if (ret <= 0) 15994235b045SMasami Hiramatsu goto error; 16004235b045SMasami Hiramatsu 16014235b045SMasami Hiramatsu return buf; 16024235b045SMasami Hiramatsu error: 16035f03cba4SMasami Hiramatsu pr_debug("Failed to synthesize perf probe point: %d\n", ret); 1604146a1439SMasami Hiramatsu free(buf); 1605146a1439SMasami Hiramatsu return NULL; 16064235b045SMasami Hiramatsu } 16074235b045SMasami Hiramatsu 16084235b045SMasami Hiramatsu #if 0 16094235b045SMasami Hiramatsu char *synthesize_perf_probe_command(struct perf_probe_event *pev) 16104235b045SMasami Hiramatsu { 16114235b045SMasami Hiramatsu char *buf; 16124235b045SMasami Hiramatsu int i, len, ret; 16134235b045SMasami Hiramatsu 16144235b045SMasami Hiramatsu buf = synthesize_perf_probe_point(&pev->point); 16154235b045SMasami Hiramatsu if (!buf) 16164235b045SMasami Hiramatsu return NULL; 16174235b045SMasami Hiramatsu 16184235b045SMasami Hiramatsu len = strlen(buf); 16194235b045SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) { 16204235b045SMasami Hiramatsu ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 16214235b045SMasami Hiramatsu pev->args[i].name); 16227ef17aafSMasami Hiramatsu if (ret <= 0) { 16234235b045SMasami Hiramatsu free(buf); 16244235b045SMasami Hiramatsu return NULL; 16257ef17aafSMasami Hiramatsu } 16264235b045SMasami Hiramatsu len += ret; 16277ef17aafSMasami Hiramatsu } 162850656eecSMasami Hiramatsu 16294235b045SMasami Hiramatsu return buf; 16304235b045SMasami Hiramatsu } 16314235b045SMasami Hiramatsu #endif 16324235b045SMasami Hiramatsu 16330e60836bSSrikar Dronamraju static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, 16344235b045SMasami Hiramatsu char **buf, size_t *buflen, 16354235b045SMasami Hiramatsu int depth) 16367ef17aafSMasami Hiramatsu { 16374235b045SMasami Hiramatsu int ret; 16384235b045SMasami Hiramatsu if (ref->next) { 16390e60836bSSrikar Dronamraju depth = __synthesize_probe_trace_arg_ref(ref->next, buf, 16404235b045SMasami Hiramatsu buflen, depth + 1); 16414235b045SMasami Hiramatsu if (depth < 0) 16424235b045SMasami Hiramatsu goto out; 16434235b045SMasami Hiramatsu } 16444235b045SMasami Hiramatsu 16454235b045SMasami Hiramatsu ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset); 16464235b045SMasami Hiramatsu if (ret < 0) 16474235b045SMasami Hiramatsu depth = ret; 16484235b045SMasami Hiramatsu else { 16494235b045SMasami Hiramatsu *buf += ret; 16504235b045SMasami Hiramatsu *buflen -= ret; 16514235b045SMasami Hiramatsu } 16524235b045SMasami Hiramatsu out: 16534235b045SMasami Hiramatsu return depth; 16544235b045SMasami Hiramatsu 16554235b045SMasami Hiramatsu } 16564235b045SMasami Hiramatsu 16570e60836bSSrikar Dronamraju static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, 16584235b045SMasami Hiramatsu char *buf, size_t buflen) 16594235b045SMasami Hiramatsu { 16600e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref = arg->ref; 16614235b045SMasami Hiramatsu int ret, depth = 0; 16624235b045SMasami Hiramatsu char *tmp = buf; 16634235b045SMasami Hiramatsu 16644235b045SMasami Hiramatsu /* Argument name or separator */ 16654235b045SMasami Hiramatsu if (arg->name) 16664235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, " %s=", arg->name); 16674235b045SMasami Hiramatsu else 16684235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, " "); 16694235b045SMasami Hiramatsu if (ret < 0) 16704235b045SMasami Hiramatsu return ret; 16714235b045SMasami Hiramatsu buf += ret; 16724235b045SMasami Hiramatsu buflen -= ret; 16734235b045SMasami Hiramatsu 1674b7dcb857SMasami Hiramatsu /* Special case: @XXX */ 1675b7dcb857SMasami Hiramatsu if (arg->value[0] == '@' && arg->ref) 1676b7dcb857SMasami Hiramatsu ref = ref->next; 1677b7dcb857SMasami Hiramatsu 16784235b045SMasami Hiramatsu /* Dereferencing arguments */ 1679b7dcb857SMasami Hiramatsu if (ref) { 16800e60836bSSrikar Dronamraju depth = __synthesize_probe_trace_arg_ref(ref, &buf, 16814235b045SMasami Hiramatsu &buflen, 1); 16824235b045SMasami Hiramatsu if (depth < 0) 16834235b045SMasami Hiramatsu return depth; 16844235b045SMasami Hiramatsu } 16854235b045SMasami Hiramatsu 16864235b045SMasami Hiramatsu /* Print argument value */ 1687b7dcb857SMasami Hiramatsu if (arg->value[0] == '@' && arg->ref) 1688b7dcb857SMasami Hiramatsu ret = e_snprintf(buf, buflen, "%s%+ld", arg->value, 1689b7dcb857SMasami Hiramatsu arg->ref->offset); 1690b7dcb857SMasami Hiramatsu else 16914235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, "%s", arg->value); 16924235b045SMasami Hiramatsu if (ret < 0) 16934235b045SMasami Hiramatsu return ret; 16944235b045SMasami Hiramatsu buf += ret; 16954235b045SMasami Hiramatsu buflen -= ret; 16964235b045SMasami Hiramatsu 16974235b045SMasami Hiramatsu /* Closing */ 16984235b045SMasami Hiramatsu while (depth--) { 16994235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, ")"); 17004235b045SMasami Hiramatsu if (ret < 0) 17014235b045SMasami Hiramatsu return ret; 17024235b045SMasami Hiramatsu buf += ret; 17034235b045SMasami Hiramatsu buflen -= ret; 17044235b045SMasami Hiramatsu } 17054984912eSMasami Hiramatsu /* Print argument type */ 17064984912eSMasami Hiramatsu if (arg->type) { 17074984912eSMasami Hiramatsu ret = e_snprintf(buf, buflen, ":%s", arg->type); 17084984912eSMasami Hiramatsu if (ret <= 0) 17094984912eSMasami Hiramatsu return ret; 17104984912eSMasami Hiramatsu buf += ret; 17114984912eSMasami Hiramatsu } 17124235b045SMasami Hiramatsu 17134235b045SMasami Hiramatsu return buf - tmp; 17144235b045SMasami Hiramatsu } 17154235b045SMasami Hiramatsu 17160e60836bSSrikar Dronamraju char *synthesize_probe_trace_command(struct probe_trace_event *tev) 17174235b045SMasami Hiramatsu { 17180e60836bSSrikar Dronamraju struct probe_trace_point *tp = &tev->point; 17197ef17aafSMasami Hiramatsu char *buf; 17207ef17aafSMasami Hiramatsu int i, len, ret; 17217ef17aafSMasami Hiramatsu 1722e334016fSMasami Hiramatsu buf = zalloc(MAX_CMDLEN); 1723e334016fSMasami Hiramatsu if (buf == NULL) 1724e334016fSMasami Hiramatsu return NULL; 1725e334016fSMasami Hiramatsu 1726eb948e50SMasami Hiramatsu len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p', 1727eb948e50SMasami Hiramatsu tev->group, tev->event); 1728eb948e50SMasami Hiramatsu if (len <= 0) 1729eb948e50SMasami Hiramatsu goto error; 1730eb948e50SMasami Hiramatsu 1731eb948e50SMasami Hiramatsu /* Uprobes must have tp->address and tp->module */ 1732eb948e50SMasami Hiramatsu if (tev->uprobes && (!tp->address || !tp->module)) 1733eb948e50SMasami Hiramatsu goto error; 1734eb948e50SMasami Hiramatsu 1735eb948e50SMasami Hiramatsu /* Use the tp->address for uprobes */ 1736225466f1SSrikar Dronamraju if (tev->uprobes) 1737eb948e50SMasami Hiramatsu ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx", 1738eb948e50SMasami Hiramatsu tp->module, tp->address); 1739225466f1SSrikar Dronamraju else 1740eb948e50SMasami Hiramatsu ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu", 1741190b57fcSMasami Hiramatsu tp->module ?: "", tp->module ? ":" : "", 17424235b045SMasami Hiramatsu tp->symbol, tp->offset); 1743225466f1SSrikar Dronamraju 1744eb948e50SMasami Hiramatsu if (ret <= 0) 17454235b045SMasami Hiramatsu goto error; 1746eb948e50SMasami Hiramatsu len += ret; 17477ef17aafSMasami Hiramatsu 17484235b045SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 17490e60836bSSrikar Dronamraju ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, 17504235b045SMasami Hiramatsu MAX_CMDLEN - len); 17514de189feSMasami Hiramatsu if (ret <= 0) 175250656eecSMasami Hiramatsu goto error; 175350656eecSMasami Hiramatsu len += ret; 175450656eecSMasami Hiramatsu } 175550656eecSMasami Hiramatsu 17564235b045SMasami Hiramatsu return buf; 175750656eecSMasami Hiramatsu error: 17584235b045SMasami Hiramatsu free(buf); 17594235b045SMasami Hiramatsu return NULL; 176050656eecSMasami Hiramatsu } 176150656eecSMasami Hiramatsu 17625a6f6314SMasami Hiramatsu static int find_perf_probe_point_from_map(struct probe_trace_point *tp, 17635a6f6314SMasami Hiramatsu struct perf_probe_point *pp, 17645a6f6314SMasami Hiramatsu bool is_kprobe) 17655a6f6314SMasami Hiramatsu { 17665a6f6314SMasami Hiramatsu struct symbol *sym = NULL; 17675a6f6314SMasami Hiramatsu struct map *map; 17685a6f6314SMasami Hiramatsu u64 addr; 17695a6f6314SMasami Hiramatsu int ret = -ENOENT; 17705a6f6314SMasami Hiramatsu 17715a6f6314SMasami Hiramatsu if (!is_kprobe) { 17725a6f6314SMasami Hiramatsu map = dso__new_map(tp->module); 17735a6f6314SMasami Hiramatsu if (!map) 17745a6f6314SMasami Hiramatsu goto out; 17755a6f6314SMasami Hiramatsu addr = tp->address; 17765a6f6314SMasami Hiramatsu sym = map__find_symbol(map, addr, NULL); 17775a6f6314SMasami Hiramatsu } else { 17785a6f6314SMasami Hiramatsu addr = kernel_get_symbol_address_by_name(tp->symbol, true); 17795a6f6314SMasami Hiramatsu if (addr) { 17805a6f6314SMasami Hiramatsu addr += tp->offset; 17815a6f6314SMasami Hiramatsu sym = __find_kernel_function(addr, &map); 17825a6f6314SMasami Hiramatsu } 17835a6f6314SMasami Hiramatsu } 17845a6f6314SMasami Hiramatsu if (!sym) 17855a6f6314SMasami Hiramatsu goto out; 17865a6f6314SMasami Hiramatsu 17875a6f6314SMasami Hiramatsu pp->retprobe = tp->retprobe; 17885a6f6314SMasami Hiramatsu pp->offset = addr - map->unmap_ip(map, sym->start); 17895a6f6314SMasami Hiramatsu pp->function = strdup(sym->name); 17905a6f6314SMasami Hiramatsu ret = pp->function ? 0 : -ENOMEM; 17915a6f6314SMasami Hiramatsu 17925a6f6314SMasami Hiramatsu out: 17935a6f6314SMasami Hiramatsu if (map && !is_kprobe) { 17945a6f6314SMasami Hiramatsu map__delete(map); 17955a6f6314SMasami Hiramatsu } 17965a6f6314SMasami Hiramatsu 17975a6f6314SMasami Hiramatsu return ret; 17985a6f6314SMasami Hiramatsu } 17995a6f6314SMasami Hiramatsu 18005a6f6314SMasami Hiramatsu static int convert_to_perf_probe_point(struct probe_trace_point *tp, 18015a6f6314SMasami Hiramatsu struct perf_probe_point *pp, 18025a6f6314SMasami Hiramatsu bool is_kprobe) 18035a6f6314SMasami Hiramatsu { 18045a6f6314SMasami Hiramatsu char buf[128]; 18055a6f6314SMasami Hiramatsu int ret; 18065a6f6314SMasami Hiramatsu 18075a6f6314SMasami Hiramatsu ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe); 18085a6f6314SMasami Hiramatsu if (!ret) 18095a6f6314SMasami Hiramatsu return 0; 18105a6f6314SMasami Hiramatsu ret = find_perf_probe_point_from_map(tp, pp, is_kprobe); 18115a6f6314SMasami Hiramatsu if (!ret) 18125a6f6314SMasami Hiramatsu return 0; 18135a6f6314SMasami Hiramatsu 18145a6f6314SMasami Hiramatsu pr_debug("Failed to find probe point from both of dwarf and map.\n"); 18155a6f6314SMasami Hiramatsu 18165a6f6314SMasami Hiramatsu if (tp->symbol) { 18175a6f6314SMasami Hiramatsu pp->function = strdup(tp->symbol); 18185a6f6314SMasami Hiramatsu pp->offset = tp->offset; 18195a6f6314SMasami Hiramatsu } else if (!tp->module && !is_kprobe) { 18205a6f6314SMasami Hiramatsu ret = e_snprintf(buf, 128, "0x%" PRIx64, (u64)tp->address); 18215a6f6314SMasami Hiramatsu if (ret < 0) 18225a6f6314SMasami Hiramatsu return ret; 18235a6f6314SMasami Hiramatsu pp->function = strdup(buf); 18245a6f6314SMasami Hiramatsu pp->offset = 0; 18255a6f6314SMasami Hiramatsu } 18265a6f6314SMasami Hiramatsu if (pp->function == NULL) 18275a6f6314SMasami Hiramatsu return -ENOMEM; 18285a6f6314SMasami Hiramatsu 18295a6f6314SMasami Hiramatsu pp->retprobe = tp->retprobe; 18305a6f6314SMasami Hiramatsu 18315a6f6314SMasami Hiramatsu return 0; 18325a6f6314SMasami Hiramatsu } 18335a6f6314SMasami Hiramatsu 18340e60836bSSrikar Dronamraju static int convert_to_perf_probe_event(struct probe_trace_event *tev, 1835225466f1SSrikar Dronamraju struct perf_probe_event *pev, bool is_kprobe) 18364de189feSMasami Hiramatsu { 183702b95dadSMasami Hiramatsu char buf[64] = ""; 1838146a1439SMasami Hiramatsu int i, ret; 18394de189feSMasami Hiramatsu 18404b4da7f7SMasami Hiramatsu /* Convert event/group name */ 184102b95dadSMasami Hiramatsu pev->event = strdup(tev->event); 184202b95dadSMasami Hiramatsu pev->group = strdup(tev->group); 184302b95dadSMasami Hiramatsu if (pev->event == NULL || pev->group == NULL) 184402b95dadSMasami Hiramatsu return -ENOMEM; 1845fb1587d8SMasami Hiramatsu 18464b4da7f7SMasami Hiramatsu /* Convert trace_point to probe_point */ 18475a6f6314SMasami Hiramatsu ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe); 1848146a1439SMasami Hiramatsu if (ret < 0) 1849146a1439SMasami Hiramatsu return ret; 18504b4da7f7SMasami Hiramatsu 18514235b045SMasami Hiramatsu /* Convert trace_arg to probe_arg */ 18524235b045SMasami Hiramatsu pev->nargs = tev->nargs; 1853e334016fSMasami Hiramatsu pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); 1854e334016fSMasami Hiramatsu if (pev->args == NULL) 1855e334016fSMasami Hiramatsu return -ENOMEM; 185602b95dadSMasami Hiramatsu for (i = 0; i < tev->nargs && ret >= 0; i++) { 18574235b045SMasami Hiramatsu if (tev->args[i].name) 185802b95dadSMasami Hiramatsu pev->args[i].name = strdup(tev->args[i].name); 18594235b045SMasami Hiramatsu else { 18600e60836bSSrikar Dronamraju ret = synthesize_probe_trace_arg(&tev->args[i], 1861146a1439SMasami Hiramatsu buf, 64); 186202b95dadSMasami Hiramatsu pev->args[i].name = strdup(buf); 186302b95dadSMasami Hiramatsu } 186402b95dadSMasami Hiramatsu if (pev->args[i].name == NULL && ret >= 0) 186502b95dadSMasami Hiramatsu ret = -ENOMEM; 18664de189feSMasami Hiramatsu } 1867146a1439SMasami Hiramatsu 1868146a1439SMasami Hiramatsu if (ret < 0) 1869146a1439SMasami Hiramatsu clear_perf_probe_event(pev); 1870146a1439SMasami Hiramatsu 1871146a1439SMasami Hiramatsu return ret; 18724235b045SMasami Hiramatsu } 18734de189feSMasami Hiramatsu 18744235b045SMasami Hiramatsu void clear_perf_probe_event(struct perf_probe_event *pev) 18754235b045SMasami Hiramatsu { 18767df2f329SMasami Hiramatsu struct perf_probe_arg_field *field, *next; 18774235b045SMasami Hiramatsu int i; 18784de189feSMasami Hiramatsu 18794235b045SMasami Hiramatsu free(pev->event); 18804235b045SMasami Hiramatsu free(pev->group); 18817afb3fabSMasami Hiramatsu free(pev->target); 18829b118acaSMasami Hiramatsu clear_perf_probe_point(&pev->point); 1883f5385650SArnaldo Carvalho de Melo 18847df2f329SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) { 18854235b045SMasami Hiramatsu free(pev->args[i].name); 188648481938SMasami Hiramatsu free(pev->args[i].var); 188711a1ca35SMasami Hiramatsu free(pev->args[i].type); 18887df2f329SMasami Hiramatsu field = pev->args[i].field; 18897df2f329SMasami Hiramatsu while (field) { 18907df2f329SMasami Hiramatsu next = field->next; 189174cf249dSArnaldo Carvalho de Melo zfree(&field->name); 18927df2f329SMasami Hiramatsu free(field); 18937df2f329SMasami Hiramatsu field = next; 18947df2f329SMasami Hiramatsu } 18957df2f329SMasami Hiramatsu } 18964235b045SMasami Hiramatsu free(pev->args); 18974235b045SMasami Hiramatsu memset(pev, 0, sizeof(*pev)); 18984235b045SMasami Hiramatsu } 18994235b045SMasami Hiramatsu 19000e60836bSSrikar Dronamraju static void clear_probe_trace_event(struct probe_trace_event *tev) 19014235b045SMasami Hiramatsu { 19020e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref, *next; 19034235b045SMasami Hiramatsu int i; 19044235b045SMasami Hiramatsu 19054235b045SMasami Hiramatsu free(tev->event); 19064235b045SMasami Hiramatsu free(tev->group); 19074235b045SMasami Hiramatsu free(tev->point.symbol); 19084c859351SMasami Hiramatsu free(tev->point.realname); 1909190b57fcSMasami Hiramatsu free(tev->point.module); 19104235b045SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 19114235b045SMasami Hiramatsu free(tev->args[i].name); 19124235b045SMasami Hiramatsu free(tev->args[i].value); 19134984912eSMasami Hiramatsu free(tev->args[i].type); 19144235b045SMasami Hiramatsu ref = tev->args[i].ref; 19154235b045SMasami Hiramatsu while (ref) { 19164235b045SMasami Hiramatsu next = ref->next; 19174235b045SMasami Hiramatsu free(ref); 19184235b045SMasami Hiramatsu ref = next; 19194235b045SMasami Hiramatsu } 19204235b045SMasami Hiramatsu } 19214235b045SMasami Hiramatsu free(tev->args); 19224235b045SMasami Hiramatsu memset(tev, 0, sizeof(*tev)); 19234de189feSMasami Hiramatsu } 19244de189feSMasami Hiramatsu 19255e45187cSMasami Hiramatsu static void print_open_warning(int err, bool is_kprobe) 1926225466f1SSrikar Dronamraju { 19275f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 1928225466f1SSrikar Dronamraju 19295e45187cSMasami Hiramatsu if (err == -ENOENT) { 1930225466f1SSrikar Dronamraju const char *config; 1931225466f1SSrikar Dronamraju 1932225466f1SSrikar Dronamraju if (!is_kprobe) 1933225466f1SSrikar Dronamraju config = "CONFIG_UPROBE_EVENTS"; 1934225466f1SSrikar Dronamraju else 1935225466f1SSrikar Dronamraju config = "CONFIG_KPROBE_EVENTS"; 1936225466f1SSrikar Dronamraju 19375e45187cSMasami Hiramatsu pr_warning("%cprobe_events file does not exist" 19385e45187cSMasami Hiramatsu " - please rebuild kernel with %s.\n", 19395e45187cSMasami Hiramatsu is_kprobe ? 'k' : 'u', config); 19405e45187cSMasami Hiramatsu } else if (err == -ENOTSUP) 194123773ca1SSteven Rostedt (Red Hat) pr_warning("Tracefs or debugfs is not mounted.\n"); 19425e45187cSMasami Hiramatsu else 19435e45187cSMasami Hiramatsu pr_warning("Failed to open %cprobe_events: %s\n", 19445e45187cSMasami Hiramatsu is_kprobe ? 'k' : 'u', 19455e45187cSMasami Hiramatsu strerror_r(-err, sbuf, sizeof(sbuf))); 1946225466f1SSrikar Dronamraju } 1947225466f1SSrikar Dronamraju 1948467ec085SMasami Hiramatsu static void print_both_open_warning(int kerr, int uerr) 1949467ec085SMasami Hiramatsu { 1950467ec085SMasami Hiramatsu /* Both kprobes and uprobes are disabled, warn it. */ 1951467ec085SMasami Hiramatsu if (kerr == -ENOTSUP && uerr == -ENOTSUP) 195223773ca1SSteven Rostedt (Red Hat) pr_warning("Tracefs or debugfs is not mounted.\n"); 1953467ec085SMasami Hiramatsu else if (kerr == -ENOENT && uerr == -ENOENT) 1954467ec085SMasami Hiramatsu pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS " 1955467ec085SMasami Hiramatsu "or/and CONFIG_UPROBE_EVENTS.\n"); 1956467ec085SMasami Hiramatsu else { 19575f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 1958467ec085SMasami Hiramatsu pr_warning("Failed to open kprobe events: %s.\n", 1959467ec085SMasami Hiramatsu strerror_r(-kerr, sbuf, sizeof(sbuf))); 1960467ec085SMasami Hiramatsu pr_warning("Failed to open uprobe events: %s.\n", 1961467ec085SMasami Hiramatsu strerror_r(-uerr, sbuf, sizeof(sbuf))); 1962467ec085SMasami Hiramatsu } 1963467ec085SMasami Hiramatsu } 1964467ec085SMasami Hiramatsu 19655e45187cSMasami Hiramatsu static int open_probe_events(const char *trace_file, bool readwrite) 19664de189feSMasami Hiramatsu { 19674de189feSMasami Hiramatsu char buf[PATH_MAX]; 19687ca5989dSMasami Hiramatsu const char *__debugfs; 196923773ca1SSteven Rostedt (Red Hat) const char *tracing_dir = ""; 19704de189feSMasami Hiramatsu int ret; 19714de189feSMasami Hiramatsu 197223773ca1SSteven Rostedt (Red Hat) __debugfs = tracefs_find_mountpoint(); 197323773ca1SSteven Rostedt (Red Hat) if (__debugfs == NULL) { 197423773ca1SSteven Rostedt (Red Hat) tracing_dir = "tracing/"; 197523773ca1SSteven Rostedt (Red Hat) 19767ca5989dSMasami Hiramatsu __debugfs = debugfs_find_mountpoint(); 19775e45187cSMasami Hiramatsu if (__debugfs == NULL) 19785e45187cSMasami Hiramatsu return -ENOTSUP; 197923773ca1SSteven Rostedt (Red Hat) } 19807ca5989dSMasami Hiramatsu 198123773ca1SSteven Rostedt (Red Hat) ret = e_snprintf(buf, PATH_MAX, "%s/%s%s", 198223773ca1SSteven Rostedt (Red Hat) __debugfs, tracing_dir, trace_file); 1983146a1439SMasami Hiramatsu if (ret >= 0) { 19847ca5989dSMasami Hiramatsu pr_debug("Opening %s write=%d\n", buf, readwrite); 1985f4d7da49SMasami Hiramatsu if (readwrite && !probe_event_dry_run) 1986b8dc3984SMasami Hiramatsu ret = open(buf, O_RDWR | O_APPEND, 0); 1987f4d7da49SMasami Hiramatsu else 1988f4d7da49SMasami Hiramatsu ret = open(buf, O_RDONLY, 0); 1989f4d7da49SMasami Hiramatsu 1990225466f1SSrikar Dronamraju if (ret < 0) 19915e45187cSMasami Hiramatsu ret = -errno; 19924de189feSMasami Hiramatsu } 19934de189feSMasami Hiramatsu return ret; 19944de189feSMasami Hiramatsu } 19954de189feSMasami Hiramatsu 1996225466f1SSrikar Dronamraju static int open_kprobe_events(bool readwrite) 1997225466f1SSrikar Dronamraju { 199823773ca1SSteven Rostedt (Red Hat) return open_probe_events("kprobe_events", readwrite); 1999225466f1SSrikar Dronamraju } 2000225466f1SSrikar Dronamraju 2001225466f1SSrikar Dronamraju static int open_uprobe_events(bool readwrite) 2002225466f1SSrikar Dronamraju { 200323773ca1SSteven Rostedt (Red Hat) return open_probe_events("uprobe_events", readwrite); 2004225466f1SSrikar Dronamraju } 2005225466f1SSrikar Dronamraju 2006225466f1SSrikar Dronamraju /* Get raw string list of current kprobe_events or uprobe_events */ 20070e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_command_rawlist(int fd) 20084de189feSMasami Hiramatsu { 20094de189feSMasami Hiramatsu int ret, idx; 20104de189feSMasami Hiramatsu FILE *fp; 20114de189feSMasami Hiramatsu char buf[MAX_CMDLEN]; 20124de189feSMasami Hiramatsu char *p; 20134de189feSMasami Hiramatsu struct strlist *sl; 20144de189feSMasami Hiramatsu 20154de189feSMasami Hiramatsu sl = strlist__new(true, NULL); 20164de189feSMasami Hiramatsu 20174de189feSMasami Hiramatsu fp = fdopen(dup(fd), "r"); 20184de189feSMasami Hiramatsu while (!feof(fp)) { 20194de189feSMasami Hiramatsu p = fgets(buf, MAX_CMDLEN, fp); 20204de189feSMasami Hiramatsu if (!p) 20214de189feSMasami Hiramatsu break; 20224de189feSMasami Hiramatsu 20234de189feSMasami Hiramatsu idx = strlen(p) - 1; 20244de189feSMasami Hiramatsu if (p[idx] == '\n') 20254de189feSMasami Hiramatsu p[idx] = '\0'; 20264de189feSMasami Hiramatsu ret = strlist__add(sl, buf); 2027146a1439SMasami Hiramatsu if (ret < 0) { 20286eb08660SMasami Hiramatsu pr_debug("strlist__add failed (%d)\n", ret); 2029146a1439SMasami Hiramatsu strlist__delete(sl); 2030146a1439SMasami Hiramatsu return NULL; 2031146a1439SMasami Hiramatsu } 20324de189feSMasami Hiramatsu } 20334de189feSMasami Hiramatsu fclose(fp); 20344de189feSMasami Hiramatsu 20354de189feSMasami Hiramatsu return sl; 20364de189feSMasami Hiramatsu } 20374de189feSMasami Hiramatsu 20389aaf5a5fSMasami Hiramatsu struct kprobe_blacklist_node { 20399aaf5a5fSMasami Hiramatsu struct list_head list; 20409aaf5a5fSMasami Hiramatsu unsigned long start; 20419aaf5a5fSMasami Hiramatsu unsigned long end; 20429aaf5a5fSMasami Hiramatsu char *symbol; 20439aaf5a5fSMasami Hiramatsu }; 20449aaf5a5fSMasami Hiramatsu 20459aaf5a5fSMasami Hiramatsu static void kprobe_blacklist__delete(struct list_head *blacklist) 20469aaf5a5fSMasami Hiramatsu { 20479aaf5a5fSMasami Hiramatsu struct kprobe_blacklist_node *node; 20489aaf5a5fSMasami Hiramatsu 20499aaf5a5fSMasami Hiramatsu while (!list_empty(blacklist)) { 20509aaf5a5fSMasami Hiramatsu node = list_first_entry(blacklist, 20519aaf5a5fSMasami Hiramatsu struct kprobe_blacklist_node, list); 20529aaf5a5fSMasami Hiramatsu list_del(&node->list); 20539aaf5a5fSMasami Hiramatsu free(node->symbol); 20549aaf5a5fSMasami Hiramatsu free(node); 20559aaf5a5fSMasami Hiramatsu } 20569aaf5a5fSMasami Hiramatsu } 20579aaf5a5fSMasami Hiramatsu 20589aaf5a5fSMasami Hiramatsu static int kprobe_blacklist__load(struct list_head *blacklist) 20599aaf5a5fSMasami Hiramatsu { 20609aaf5a5fSMasami Hiramatsu struct kprobe_blacklist_node *node; 20619aaf5a5fSMasami Hiramatsu const char *__debugfs = debugfs_find_mountpoint(); 20629aaf5a5fSMasami Hiramatsu char buf[PATH_MAX], *p; 20639aaf5a5fSMasami Hiramatsu FILE *fp; 20649aaf5a5fSMasami Hiramatsu int ret; 20659aaf5a5fSMasami Hiramatsu 20669aaf5a5fSMasami Hiramatsu if (__debugfs == NULL) 20679aaf5a5fSMasami Hiramatsu return -ENOTSUP; 20689aaf5a5fSMasami Hiramatsu 20699aaf5a5fSMasami Hiramatsu ret = e_snprintf(buf, PATH_MAX, "%s/kprobes/blacklist", __debugfs); 20709aaf5a5fSMasami Hiramatsu if (ret < 0) 20719aaf5a5fSMasami Hiramatsu return ret; 20729aaf5a5fSMasami Hiramatsu 20739aaf5a5fSMasami Hiramatsu fp = fopen(buf, "r"); 20749aaf5a5fSMasami Hiramatsu if (!fp) 20759aaf5a5fSMasami Hiramatsu return -errno; 20769aaf5a5fSMasami Hiramatsu 20779aaf5a5fSMasami Hiramatsu ret = 0; 20789aaf5a5fSMasami Hiramatsu while (fgets(buf, PATH_MAX, fp)) { 20799aaf5a5fSMasami Hiramatsu node = zalloc(sizeof(*node)); 20809aaf5a5fSMasami Hiramatsu if (!node) { 20819aaf5a5fSMasami Hiramatsu ret = -ENOMEM; 20829aaf5a5fSMasami Hiramatsu break; 20839aaf5a5fSMasami Hiramatsu } 20849aaf5a5fSMasami Hiramatsu INIT_LIST_HEAD(&node->list); 20859aaf5a5fSMasami Hiramatsu list_add_tail(&node->list, blacklist); 20869aaf5a5fSMasami Hiramatsu if (sscanf(buf, "0x%lx-0x%lx", &node->start, &node->end) != 2) { 20879aaf5a5fSMasami Hiramatsu ret = -EINVAL; 20889aaf5a5fSMasami Hiramatsu break; 20899aaf5a5fSMasami Hiramatsu } 20909aaf5a5fSMasami Hiramatsu p = strchr(buf, '\t'); 20919aaf5a5fSMasami Hiramatsu if (p) { 20929aaf5a5fSMasami Hiramatsu p++; 20939aaf5a5fSMasami Hiramatsu if (p[strlen(p) - 1] == '\n') 20949aaf5a5fSMasami Hiramatsu p[strlen(p) - 1] = '\0'; 20959aaf5a5fSMasami Hiramatsu } else 20969aaf5a5fSMasami Hiramatsu p = (char *)"unknown"; 20979aaf5a5fSMasami Hiramatsu node->symbol = strdup(p); 20989aaf5a5fSMasami Hiramatsu if (!node->symbol) { 20999aaf5a5fSMasami Hiramatsu ret = -ENOMEM; 21009aaf5a5fSMasami Hiramatsu break; 21019aaf5a5fSMasami Hiramatsu } 21029aaf5a5fSMasami Hiramatsu pr_debug2("Blacklist: 0x%lx-0x%lx, %s\n", 21039aaf5a5fSMasami Hiramatsu node->start, node->end, node->symbol); 21049aaf5a5fSMasami Hiramatsu ret++; 21059aaf5a5fSMasami Hiramatsu } 21069aaf5a5fSMasami Hiramatsu if (ret < 0) 21079aaf5a5fSMasami Hiramatsu kprobe_blacklist__delete(blacklist); 21089aaf5a5fSMasami Hiramatsu fclose(fp); 21099aaf5a5fSMasami Hiramatsu 21109aaf5a5fSMasami Hiramatsu return ret; 21119aaf5a5fSMasami Hiramatsu } 21129aaf5a5fSMasami Hiramatsu 21139aaf5a5fSMasami Hiramatsu static struct kprobe_blacklist_node * 21149aaf5a5fSMasami Hiramatsu kprobe_blacklist__find_by_address(struct list_head *blacklist, 21159aaf5a5fSMasami Hiramatsu unsigned long address) 21169aaf5a5fSMasami Hiramatsu { 21179aaf5a5fSMasami Hiramatsu struct kprobe_blacklist_node *node; 21189aaf5a5fSMasami Hiramatsu 21199aaf5a5fSMasami Hiramatsu list_for_each_entry(node, blacklist, list) { 21209aaf5a5fSMasami Hiramatsu if (node->start <= address && address <= node->end) 21219aaf5a5fSMasami Hiramatsu return node; 21229aaf5a5fSMasami Hiramatsu } 21239aaf5a5fSMasami Hiramatsu 21249aaf5a5fSMasami Hiramatsu return NULL; 21259aaf5a5fSMasami Hiramatsu } 21269aaf5a5fSMasami Hiramatsu 2127278498d4SMasami Hiramatsu /* Show an event */ 2128fb226ccdSMasami Hiramatsu static int show_perf_probe_event(struct perf_probe_event *pev, 2129fb226ccdSMasami Hiramatsu const char *module) 2130278498d4SMasami Hiramatsu { 21317e990a51SMasami Hiramatsu int i, ret; 2132278498d4SMasami Hiramatsu char buf[128]; 21334235b045SMasami Hiramatsu char *place; 2134278498d4SMasami Hiramatsu 21354235b045SMasami Hiramatsu /* Synthesize only event probe point */ 21364235b045SMasami Hiramatsu place = synthesize_perf_probe_point(&pev->point); 2137146a1439SMasami Hiramatsu if (!place) 2138146a1439SMasami Hiramatsu return -EINVAL; 21394235b045SMasami Hiramatsu 21404235b045SMasami Hiramatsu ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); 21417e990a51SMasami Hiramatsu if (ret < 0) 2142146a1439SMasami Hiramatsu return ret; 2143146a1439SMasami Hiramatsu 21445e17b28fSMasami Hiramatsu pr_info(" %-20s (on %s", buf, place); 2145fb226ccdSMasami Hiramatsu if (module) 21465e17b28fSMasami Hiramatsu pr_info(" in %s", module); 2147278498d4SMasami Hiramatsu 21484235b045SMasami Hiramatsu if (pev->nargs > 0) { 21495e17b28fSMasami Hiramatsu pr_info(" with"); 21507df2f329SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) { 2151146a1439SMasami Hiramatsu ret = synthesize_perf_probe_arg(&pev->args[i], 2152146a1439SMasami Hiramatsu buf, 128); 2153146a1439SMasami Hiramatsu if (ret < 0) 2154146a1439SMasami Hiramatsu break; 21555e17b28fSMasami Hiramatsu pr_info(" %s", buf); 21567df2f329SMasami Hiramatsu } 2157278498d4SMasami Hiramatsu } 21585e17b28fSMasami Hiramatsu pr_info(")\n"); 21594235b045SMasami Hiramatsu free(place); 2160146a1439SMasami Hiramatsu return ret; 2161278498d4SMasami Hiramatsu } 2162278498d4SMasami Hiramatsu 2163b6a89643SMasami Hiramatsu static bool filter_probe_trace_event(struct probe_trace_event *tev, 2164b6a89643SMasami Hiramatsu struct strfilter *filter) 2165b6a89643SMasami Hiramatsu { 2166b6a89643SMasami Hiramatsu char tmp[128]; 2167b6a89643SMasami Hiramatsu 2168b6a89643SMasami Hiramatsu /* At first, check the event name itself */ 2169b6a89643SMasami Hiramatsu if (strfilter__compare(filter, tev->event)) 2170b6a89643SMasami Hiramatsu return true; 2171b6a89643SMasami Hiramatsu 2172b6a89643SMasami Hiramatsu /* Next, check the combination of name and group */ 2173b6a89643SMasami Hiramatsu if (e_snprintf(tmp, 128, "%s:%s", tev->group, tev->event) < 0) 2174b6a89643SMasami Hiramatsu return false; 2175b6a89643SMasami Hiramatsu return strfilter__compare(filter, tmp); 2176b6a89643SMasami Hiramatsu } 2177b6a89643SMasami Hiramatsu 2178b6a89643SMasami Hiramatsu static int __show_perf_probe_events(int fd, bool is_kprobe, 2179b6a89643SMasami Hiramatsu struct strfilter *filter) 21804de189feSMasami Hiramatsu { 2181225466f1SSrikar Dronamraju int ret = 0; 21820e60836bSSrikar Dronamraju struct probe_trace_event tev; 21834235b045SMasami Hiramatsu struct perf_probe_event pev; 21844de189feSMasami Hiramatsu struct strlist *rawlist; 21854de189feSMasami Hiramatsu struct str_node *ent; 21864de189feSMasami Hiramatsu 21874235b045SMasami Hiramatsu memset(&tev, 0, sizeof(tev)); 21884235b045SMasami Hiramatsu memset(&pev, 0, sizeof(pev)); 218972041334SMasami Hiramatsu 21900e60836bSSrikar Dronamraju rawlist = get_probe_trace_command_rawlist(fd); 2191146a1439SMasami Hiramatsu if (!rawlist) 21926eb08660SMasami Hiramatsu return -ENOMEM; 21934de189feSMasami Hiramatsu 2194adf365f4SMasami Hiramatsu strlist__for_each(ent, rawlist) { 21950e60836bSSrikar Dronamraju ret = parse_probe_trace_command(ent->s, &tev); 2196146a1439SMasami Hiramatsu if (ret >= 0) { 2197b6a89643SMasami Hiramatsu if (!filter_probe_trace_event(&tev, filter)) 2198b6a89643SMasami Hiramatsu goto next; 2199225466f1SSrikar Dronamraju ret = convert_to_perf_probe_event(&tev, &pev, 2200225466f1SSrikar Dronamraju is_kprobe); 2201146a1439SMasami Hiramatsu if (ret >= 0) 2202fb226ccdSMasami Hiramatsu ret = show_perf_probe_event(&pev, 2203fb226ccdSMasami Hiramatsu tev.point.module); 2204146a1439SMasami Hiramatsu } 2205b6a89643SMasami Hiramatsu next: 22064235b045SMasami Hiramatsu clear_perf_probe_event(&pev); 22070e60836bSSrikar Dronamraju clear_probe_trace_event(&tev); 2208146a1439SMasami Hiramatsu if (ret < 0) 2209146a1439SMasami Hiramatsu break; 22104de189feSMasami Hiramatsu } 22114de189feSMasami Hiramatsu strlist__delete(rawlist); 2212146a1439SMasami Hiramatsu 2213146a1439SMasami Hiramatsu return ret; 22144de189feSMasami Hiramatsu } 22154de189feSMasami Hiramatsu 2216225466f1SSrikar Dronamraju /* List up current perf-probe events */ 2217b6a89643SMasami Hiramatsu int show_perf_probe_events(struct strfilter *filter) 2218225466f1SSrikar Dronamraju { 22195e45187cSMasami Hiramatsu int kp_fd, up_fd, ret; 2220225466f1SSrikar Dronamraju 2221225466f1SSrikar Dronamraju setup_pager(); 2222225466f1SSrikar Dronamraju 2223ee45b6c2SMasami Hiramatsu ret = init_symbol_maps(false); 2224225466f1SSrikar Dronamraju if (ret < 0) 2225225466f1SSrikar Dronamraju return ret; 2226225466f1SSrikar Dronamraju 22275e45187cSMasami Hiramatsu kp_fd = open_kprobe_events(false); 22285e45187cSMasami Hiramatsu if (kp_fd >= 0) { 2229b6a89643SMasami Hiramatsu ret = __show_perf_probe_events(kp_fd, true, filter); 22305e45187cSMasami Hiramatsu close(kp_fd); 22315e45187cSMasami Hiramatsu if (ret < 0) 22325e45187cSMasami Hiramatsu goto out; 2233225466f1SSrikar Dronamraju } 2234225466f1SSrikar Dronamraju 22355e45187cSMasami Hiramatsu up_fd = open_uprobe_events(false); 22365e45187cSMasami Hiramatsu if (kp_fd < 0 && up_fd < 0) { 2237467ec085SMasami Hiramatsu print_both_open_warning(kp_fd, up_fd); 22385e45187cSMasami Hiramatsu ret = kp_fd; 22395e45187cSMasami Hiramatsu goto out; 22405e45187cSMasami Hiramatsu } 22415e45187cSMasami Hiramatsu 22425e45187cSMasami Hiramatsu if (up_fd >= 0) { 2243b6a89643SMasami Hiramatsu ret = __show_perf_probe_events(up_fd, false, filter); 22445e45187cSMasami Hiramatsu close(up_fd); 22455e45187cSMasami Hiramatsu } 22465e45187cSMasami Hiramatsu out: 2247ee45b6c2SMasami Hiramatsu exit_symbol_maps(); 2248225466f1SSrikar Dronamraju return ret; 2249225466f1SSrikar Dronamraju } 2250225466f1SSrikar Dronamraju 2251b498ce1fSMasami Hiramatsu /* Get current perf-probe event names */ 22520e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_event_names(int fd, bool include_group) 2253b498ce1fSMasami Hiramatsu { 2254fa28244dSMasami Hiramatsu char buf[128]; 2255b498ce1fSMasami Hiramatsu struct strlist *sl, *rawlist; 2256b498ce1fSMasami Hiramatsu struct str_node *ent; 22570e60836bSSrikar Dronamraju struct probe_trace_event tev; 2258146a1439SMasami Hiramatsu int ret = 0; 2259b498ce1fSMasami Hiramatsu 22604235b045SMasami Hiramatsu memset(&tev, 0, sizeof(tev)); 22610e60836bSSrikar Dronamraju rawlist = get_probe_trace_command_rawlist(fd); 22626eb08660SMasami Hiramatsu if (!rawlist) 22636eb08660SMasami Hiramatsu return NULL; 2264e1d2017bSMasami Hiramatsu sl = strlist__new(true, NULL); 2265adf365f4SMasami Hiramatsu strlist__for_each(ent, rawlist) { 22660e60836bSSrikar Dronamraju ret = parse_probe_trace_command(ent->s, &tev); 2267146a1439SMasami Hiramatsu if (ret < 0) 2268146a1439SMasami Hiramatsu break; 2269fa28244dSMasami Hiramatsu if (include_group) { 2270146a1439SMasami Hiramatsu ret = e_snprintf(buf, 128, "%s:%s", tev.group, 2271146a1439SMasami Hiramatsu tev.event); 2272146a1439SMasami Hiramatsu if (ret >= 0) 2273146a1439SMasami Hiramatsu ret = strlist__add(sl, buf); 2274fa28244dSMasami Hiramatsu } else 2275146a1439SMasami Hiramatsu ret = strlist__add(sl, tev.event); 22760e60836bSSrikar Dronamraju clear_probe_trace_event(&tev); 2277146a1439SMasami Hiramatsu if (ret < 0) 2278146a1439SMasami Hiramatsu break; 2279b498ce1fSMasami Hiramatsu } 2280b498ce1fSMasami Hiramatsu strlist__delete(rawlist); 2281b498ce1fSMasami Hiramatsu 2282146a1439SMasami Hiramatsu if (ret < 0) { 2283146a1439SMasami Hiramatsu strlist__delete(sl); 2284146a1439SMasami Hiramatsu return NULL; 2285146a1439SMasami Hiramatsu } 2286b498ce1fSMasami Hiramatsu return sl; 2287b498ce1fSMasami Hiramatsu } 2288b498ce1fSMasami Hiramatsu 22890e60836bSSrikar Dronamraju static int write_probe_trace_event(int fd, struct probe_trace_event *tev) 229050656eecSMasami Hiramatsu { 22916eca8cc3SFrederic Weisbecker int ret = 0; 22920e60836bSSrikar Dronamraju char *buf = synthesize_probe_trace_command(tev); 22935f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 229450656eecSMasami Hiramatsu 2295146a1439SMasami Hiramatsu if (!buf) { 22960e60836bSSrikar Dronamraju pr_debug("Failed to synthesize probe trace event.\n"); 2297146a1439SMasami Hiramatsu return -EINVAL; 2298146a1439SMasami Hiramatsu } 2299146a1439SMasami Hiramatsu 2300fa28244dSMasami Hiramatsu pr_debug("Writing event: %s\n", buf); 2301f4d7da49SMasami Hiramatsu if (!probe_event_dry_run) { 230250656eecSMasami Hiramatsu ret = write(fd, buf, strlen(buf)); 23037949ba1fSNamhyung Kim if (ret <= 0) { 23047949ba1fSNamhyung Kim ret = -errno; 2305146a1439SMasami Hiramatsu pr_warning("Failed to write event: %s\n", 23065f03cba4SMasami Hiramatsu strerror_r(errno, sbuf, sizeof(sbuf))); 230750656eecSMasami Hiramatsu } 23087949ba1fSNamhyung Kim } 23094235b045SMasami Hiramatsu free(buf); 2310146a1439SMasami Hiramatsu return ret; 2311f4d7da49SMasami Hiramatsu } 231250656eecSMasami Hiramatsu 2313146a1439SMasami Hiramatsu static int get_new_event_name(char *buf, size_t len, const char *base, 2314d761b08bSMasami Hiramatsu struct strlist *namelist, bool allow_suffix) 2315b498ce1fSMasami Hiramatsu { 2316b498ce1fSMasami Hiramatsu int i, ret; 231717f88fcdSMasami Hiramatsu 23183099c026SNaveen N. Rao if (*base == '.') 23193099c026SNaveen N. Rao base++; 23203099c026SNaveen N. Rao 232117f88fcdSMasami Hiramatsu /* Try no suffix */ 232217f88fcdSMasami Hiramatsu ret = e_snprintf(buf, len, "%s", base); 2323146a1439SMasami Hiramatsu if (ret < 0) { 23245f03cba4SMasami Hiramatsu pr_debug("snprintf() failed: %d\n", ret); 2325146a1439SMasami Hiramatsu return ret; 2326146a1439SMasami Hiramatsu } 232717f88fcdSMasami Hiramatsu if (!strlist__has_entry(namelist, buf)) 2328146a1439SMasami Hiramatsu return 0; 232917f88fcdSMasami Hiramatsu 2330d761b08bSMasami Hiramatsu if (!allow_suffix) { 2331d761b08bSMasami Hiramatsu pr_warning("Error: event \"%s\" already exists. " 2332d761b08bSMasami Hiramatsu "(Use -f to force duplicates.)\n", base); 2333146a1439SMasami Hiramatsu return -EEXIST; 2334d761b08bSMasami Hiramatsu } 2335d761b08bSMasami Hiramatsu 233617f88fcdSMasami Hiramatsu /* Try to add suffix */ 233717f88fcdSMasami Hiramatsu for (i = 1; i < MAX_EVENT_INDEX; i++) { 2338b498ce1fSMasami Hiramatsu ret = e_snprintf(buf, len, "%s_%d", base, i); 2339146a1439SMasami Hiramatsu if (ret < 0) { 23405f03cba4SMasami Hiramatsu pr_debug("snprintf() failed: %d\n", ret); 2341146a1439SMasami Hiramatsu return ret; 2342146a1439SMasami Hiramatsu } 2343b498ce1fSMasami Hiramatsu if (!strlist__has_entry(namelist, buf)) 2344b498ce1fSMasami Hiramatsu break; 2345b498ce1fSMasami Hiramatsu } 2346146a1439SMasami Hiramatsu if (i == MAX_EVENT_INDEX) { 2347146a1439SMasami Hiramatsu pr_warning("Too many events are on the same function.\n"); 2348146a1439SMasami Hiramatsu ret = -ERANGE; 2349b498ce1fSMasami Hiramatsu } 2350b498ce1fSMasami Hiramatsu 2351146a1439SMasami Hiramatsu return ret; 2352146a1439SMasami Hiramatsu } 2353146a1439SMasami Hiramatsu 235479702f61SMasami Hiramatsu /* Warn if the current kernel's uprobe implementation is old */ 235579702f61SMasami Hiramatsu static void warn_uprobe_event_compat(struct probe_trace_event *tev) 235679702f61SMasami Hiramatsu { 235779702f61SMasami Hiramatsu int i; 235879702f61SMasami Hiramatsu char *buf = synthesize_probe_trace_command(tev); 235979702f61SMasami Hiramatsu 236079702f61SMasami Hiramatsu /* Old uprobe event doesn't support memory dereference */ 236179702f61SMasami Hiramatsu if (!tev->uprobes || tev->nargs == 0 || !buf) 236279702f61SMasami Hiramatsu goto out; 236379702f61SMasami Hiramatsu 236479702f61SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) 236579702f61SMasami Hiramatsu if (strglobmatch(tev->args[i].value, "[$@+-]*")) { 236679702f61SMasami Hiramatsu pr_warning("Please upgrade your kernel to at least " 236779702f61SMasami Hiramatsu "3.14 to have access to feature %s\n", 236879702f61SMasami Hiramatsu tev->args[i].value); 236979702f61SMasami Hiramatsu break; 237079702f61SMasami Hiramatsu } 237179702f61SMasami Hiramatsu out: 237279702f61SMasami Hiramatsu free(buf); 237379702f61SMasami Hiramatsu } 237479702f61SMasami Hiramatsu 23750e60836bSSrikar Dronamraju static int __add_probe_trace_events(struct perf_probe_event *pev, 23760e60836bSSrikar Dronamraju struct probe_trace_event *tevs, 23774235b045SMasami Hiramatsu int ntevs, bool allow_suffix) 237850656eecSMasami Hiramatsu { 2379146a1439SMasami Hiramatsu int i, fd, ret; 23800e60836bSSrikar Dronamraju struct probe_trace_event *tev = NULL; 23814235b045SMasami Hiramatsu char buf[64]; 23824235b045SMasami Hiramatsu const char *event, *group; 2383b498ce1fSMasami Hiramatsu struct strlist *namelist; 23849aaf5a5fSMasami Hiramatsu LIST_HEAD(blacklist); 23859aaf5a5fSMasami Hiramatsu struct kprobe_blacklist_node *node; 23864c859351SMasami Hiramatsu bool safename; 238750656eecSMasami Hiramatsu 2388225466f1SSrikar Dronamraju if (pev->uprobes) 2389225466f1SSrikar Dronamraju fd = open_uprobe_events(true); 2390225466f1SSrikar Dronamraju else 2391f4d7da49SMasami Hiramatsu fd = open_kprobe_events(true); 2392225466f1SSrikar Dronamraju 23935e45187cSMasami Hiramatsu if (fd < 0) { 23945e45187cSMasami Hiramatsu print_open_warning(fd, !pev->uprobes); 2395146a1439SMasami Hiramatsu return fd; 23965e45187cSMasami Hiramatsu } 23975e45187cSMasami Hiramatsu 2398b498ce1fSMasami Hiramatsu /* Get current event names */ 23990e60836bSSrikar Dronamraju namelist = get_probe_trace_event_names(fd, false); 2400146a1439SMasami Hiramatsu if (!namelist) { 2401146a1439SMasami Hiramatsu pr_debug("Failed to get current event list.\n"); 2402ae2cb1acSMasami Hiramatsu ret = -ENOMEM; 2403ae2cb1acSMasami Hiramatsu goto close_out; 2404146a1439SMasami Hiramatsu } 24059aaf5a5fSMasami Hiramatsu /* Get kprobe blacklist if exists */ 24069aaf5a5fSMasami Hiramatsu if (!pev->uprobes) { 24079aaf5a5fSMasami Hiramatsu ret = kprobe_blacklist__load(&blacklist); 24089aaf5a5fSMasami Hiramatsu if (ret < 0) 24099aaf5a5fSMasami Hiramatsu pr_debug("No kprobe blacklist support, ignored\n"); 24109aaf5a5fSMasami Hiramatsu } 241150656eecSMasami Hiramatsu 24124c859351SMasami Hiramatsu safename = (pev->point.function && !strisglob(pev->point.function)); 2413146a1439SMasami Hiramatsu ret = 0; 24145e17b28fSMasami Hiramatsu pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":"); 241502b95dadSMasami Hiramatsu for (i = 0; i < ntevs; i++) { 24164235b045SMasami Hiramatsu tev = &tevs[i]; 24175a51fcd1SMasami Hiramatsu /* Skip if the symbol is out of .text (marked previously) */ 24185a51fcd1SMasami Hiramatsu if (!tev->point.symbol) 24195a51fcd1SMasami Hiramatsu continue; 24209aaf5a5fSMasami Hiramatsu /* Ensure that the address is NOT blacklisted */ 24219aaf5a5fSMasami Hiramatsu node = kprobe_blacklist__find_by_address(&blacklist, 24229aaf5a5fSMasami Hiramatsu tev->point.address); 24239aaf5a5fSMasami Hiramatsu if (node) { 24249aaf5a5fSMasami Hiramatsu pr_warning("Warning: Skipped probing on blacklisted function: %s\n", node->symbol); 24259aaf5a5fSMasami Hiramatsu continue; 24269aaf5a5fSMasami Hiramatsu } 24279aaf5a5fSMasami Hiramatsu 24284235b045SMasami Hiramatsu if (pev->event) 24294235b045SMasami Hiramatsu event = pev->event; 24304235b045SMasami Hiramatsu else 24314c859351SMasami Hiramatsu if (safename) 24324235b045SMasami Hiramatsu event = pev->point.function; 24334235b045SMasami Hiramatsu else 24344c859351SMasami Hiramatsu event = tev->point.realname; 24354235b045SMasami Hiramatsu if (pev->group) 24364235b045SMasami Hiramatsu group = pev->group; 24374235b045SMasami Hiramatsu else 24384235b045SMasami Hiramatsu group = PERFPROBE_GROUP; 24394235b045SMasami Hiramatsu 2440b498ce1fSMasami Hiramatsu /* Get an unused new event name */ 2441146a1439SMasami Hiramatsu ret = get_new_event_name(buf, 64, event, 2442146a1439SMasami Hiramatsu namelist, allow_suffix); 2443146a1439SMasami Hiramatsu if (ret < 0) 2444146a1439SMasami Hiramatsu break; 24454235b045SMasami Hiramatsu event = buf; 24464235b045SMasami Hiramatsu 244702b95dadSMasami Hiramatsu tev->event = strdup(event); 244802b95dadSMasami Hiramatsu tev->group = strdup(group); 244902b95dadSMasami Hiramatsu if (tev->event == NULL || tev->group == NULL) { 245002b95dadSMasami Hiramatsu ret = -ENOMEM; 245102b95dadSMasami Hiramatsu break; 245202b95dadSMasami Hiramatsu } 24530e60836bSSrikar Dronamraju ret = write_probe_trace_event(fd, tev); 2454146a1439SMasami Hiramatsu if (ret < 0) 2455146a1439SMasami Hiramatsu break; 2456b498ce1fSMasami Hiramatsu /* Add added event name to namelist */ 2457b498ce1fSMasami Hiramatsu strlist__add(namelist, event); 24584235b045SMasami Hiramatsu 24594235b045SMasami Hiramatsu /* Trick here - save current event/group */ 24604235b045SMasami Hiramatsu event = pev->event; 24614235b045SMasami Hiramatsu group = pev->group; 24624235b045SMasami Hiramatsu pev->event = tev->event; 24634235b045SMasami Hiramatsu pev->group = tev->group; 2464fb226ccdSMasami Hiramatsu show_perf_probe_event(pev, tev->point.module); 24654235b045SMasami Hiramatsu /* Trick here - restore current event/group */ 24664235b045SMasami Hiramatsu pev->event = (char *)event; 24674235b045SMasami Hiramatsu pev->group = (char *)group; 24684235b045SMasami Hiramatsu 2469d761b08bSMasami Hiramatsu /* 2470d761b08bSMasami Hiramatsu * Probes after the first probe which comes from same 2471d761b08bSMasami Hiramatsu * user input are always allowed to add suffix, because 2472d761b08bSMasami Hiramatsu * there might be several addresses corresponding to 2473d761b08bSMasami Hiramatsu * one code line. 2474d761b08bSMasami Hiramatsu */ 2475d761b08bSMasami Hiramatsu allow_suffix = true; 247650656eecSMasami Hiramatsu } 247779702f61SMasami Hiramatsu if (ret == -EINVAL && pev->uprobes) 247879702f61SMasami Hiramatsu warn_uprobe_event_compat(tev); 2479146a1439SMasami Hiramatsu 24809aaf5a5fSMasami Hiramatsu /* Note that it is possible to skip all events because of blacklist */ 24819aaf5a5fSMasami Hiramatsu if (ret >= 0 && tev->event) { 2482a9b495b0SMasami Hiramatsu /* Show how to use the event. */ 24835e17b28fSMasami Hiramatsu pr_info("\nYou can now use it in all perf tools, such as:\n\n"); 24845e17b28fSMasami Hiramatsu pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, 2485146a1439SMasami Hiramatsu tev->event); 2486146a1439SMasami Hiramatsu } 2487a9b495b0SMasami Hiramatsu 24889aaf5a5fSMasami Hiramatsu kprobe_blacklist__delete(&blacklist); 2489e1d2017bSMasami Hiramatsu strlist__delete(namelist); 2490ae2cb1acSMasami Hiramatsu close_out: 249150656eecSMasami Hiramatsu close(fd); 2492146a1439SMasami Hiramatsu return ret; 249350656eecSMasami Hiramatsu } 2494fa28244dSMasami Hiramatsu 2495564c62a4SNamhyung Kim static int find_probe_functions(struct map *map, char *name) 2496eb948e50SMasami Hiramatsu { 2497564c62a4SNamhyung Kim int found = 0; 24980a3873a8SArnaldo Carvalho de Melo struct symbol *sym; 24994c859351SMasami Hiramatsu struct rb_node *tmp; 2500564c62a4SNamhyung Kim 250175e4a2a6SWang Nan if (map__load(map, NULL) < 0) 250275e4a2a6SWang Nan return 0; 250375e4a2a6SWang Nan 25044c859351SMasami Hiramatsu map__for_each_symbol(map, sym, tmp) { 25054c859351SMasami Hiramatsu if (strglobmatch(sym->name, name)) 2506564c62a4SNamhyung Kim found++; 2507eb948e50SMasami Hiramatsu } 2508564c62a4SNamhyung Kim 2509564c62a4SNamhyung Kim return found; 2510eb948e50SMasami Hiramatsu } 2511eb948e50SMasami Hiramatsu 2512eb948e50SMasami Hiramatsu #define strdup_or_goto(str, label) \ 2513eb948e50SMasami Hiramatsu ({ char *__p = strdup(str); if (!__p) goto label; __p; }) 2514eb948e50SMasami Hiramatsu 25157b6ff0bdSNaveen N. Rao void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused, 25167b6ff0bdSNaveen N. Rao struct probe_trace_event *tev __maybe_unused, 25177b6ff0bdSNaveen N. Rao struct map *map __maybe_unused) { } 25187b6ff0bdSNaveen N. Rao 2519eb948e50SMasami Hiramatsu /* 2520eb948e50SMasami Hiramatsu * Find probe function addresses from map. 2521eb948e50SMasami Hiramatsu * Return an error or the number of found probe_trace_event 2522eb948e50SMasami Hiramatsu */ 2523eb948e50SMasami Hiramatsu static int find_probe_trace_events_from_map(struct perf_probe_event *pev, 2524ddb2f58fSMasami Hiramatsu struct probe_trace_event **tevs) 2525eb948e50SMasami Hiramatsu { 2526eb948e50SMasami Hiramatsu struct map *map = NULL; 2527eb948e50SMasami Hiramatsu struct ref_reloc_sym *reloc_sym = NULL; 2528eb948e50SMasami Hiramatsu struct symbol *sym; 2529eb948e50SMasami Hiramatsu struct probe_trace_event *tev; 2530eb948e50SMasami Hiramatsu struct perf_probe_point *pp = &pev->point; 2531eb948e50SMasami Hiramatsu struct probe_trace_point *tp; 2532564c62a4SNamhyung Kim int num_matched_functions; 2533eb948e50SMasami Hiramatsu int ret, i; 2534eb948e50SMasami Hiramatsu 253544225521SMasami Hiramatsu map = get_target_map(pev->target, pev->uprobes); 2536eb948e50SMasami Hiramatsu if (!map) { 2537eb948e50SMasami Hiramatsu ret = -EINVAL; 2538eb948e50SMasami Hiramatsu goto out; 2539eb948e50SMasami Hiramatsu } 2540eb948e50SMasami Hiramatsu 2541eb948e50SMasami Hiramatsu /* 2542eb948e50SMasami Hiramatsu * Load matched symbols: Since the different local symbols may have 2543eb948e50SMasami Hiramatsu * same name but different addresses, this lists all the symbols. 2544eb948e50SMasami Hiramatsu */ 2545564c62a4SNamhyung Kim num_matched_functions = find_probe_functions(map, pp->function); 2546564c62a4SNamhyung Kim if (num_matched_functions == 0) { 2547eb948e50SMasami Hiramatsu pr_err("Failed to find symbol %s in %s\n", pp->function, 254844225521SMasami Hiramatsu pev->target ? : "kernel"); 2549eb948e50SMasami Hiramatsu ret = -ENOENT; 2550eb948e50SMasami Hiramatsu goto out; 2551ddb2f58fSMasami Hiramatsu } else if (num_matched_functions > probe_conf.max_probes) { 2552eb948e50SMasami Hiramatsu pr_err("Too many functions matched in %s\n", 255344225521SMasami Hiramatsu pev->target ? : "kernel"); 2554eb948e50SMasami Hiramatsu ret = -E2BIG; 2555eb948e50SMasami Hiramatsu goto out; 2556eb948e50SMasami Hiramatsu } 2557eb948e50SMasami Hiramatsu 255825dd9171SNamhyung Kim if (!pev->uprobes && !pp->retprobe) { 25590560a0c4SHe Kuang reloc_sym = kernel_get_ref_reloc_sym(); 2560eb948e50SMasami Hiramatsu if (!reloc_sym) { 2561eb948e50SMasami Hiramatsu pr_warning("Relocated base symbol is not found!\n"); 2562eb948e50SMasami Hiramatsu ret = -EINVAL; 2563eb948e50SMasami Hiramatsu goto out; 2564eb948e50SMasami Hiramatsu } 2565eb948e50SMasami Hiramatsu } 2566eb948e50SMasami Hiramatsu 2567eb948e50SMasami Hiramatsu /* Setup result trace-probe-events */ 2568eb948e50SMasami Hiramatsu *tevs = zalloc(sizeof(*tev) * num_matched_functions); 2569eb948e50SMasami Hiramatsu if (!*tevs) { 2570eb948e50SMasami Hiramatsu ret = -ENOMEM; 2571eb948e50SMasami Hiramatsu goto out; 2572eb948e50SMasami Hiramatsu } 2573eb948e50SMasami Hiramatsu 2574eb948e50SMasami Hiramatsu ret = 0; 2575564c62a4SNamhyung Kim 25760a3873a8SArnaldo Carvalho de Melo map__for_each_symbol_by_name(map, pp->function, sym) { 2577eb948e50SMasami Hiramatsu tev = (*tevs) + ret; 2578eb948e50SMasami Hiramatsu tp = &tev->point; 2579eb948e50SMasami Hiramatsu if (ret == num_matched_functions) { 2580eb948e50SMasami Hiramatsu pr_warning("Too many symbols are listed. Skip it.\n"); 2581eb948e50SMasami Hiramatsu break; 2582eb948e50SMasami Hiramatsu } 2583eb948e50SMasami Hiramatsu ret++; 2584eb948e50SMasami Hiramatsu 2585eb948e50SMasami Hiramatsu if (pp->offset > sym->end - sym->start) { 2586eb948e50SMasami Hiramatsu pr_warning("Offset %ld is bigger than the size of %s\n", 2587eb948e50SMasami Hiramatsu pp->offset, sym->name); 2588eb948e50SMasami Hiramatsu ret = -ENOENT; 2589eb948e50SMasami Hiramatsu goto err_out; 2590eb948e50SMasami Hiramatsu } 2591eb948e50SMasami Hiramatsu /* Add one probe point */ 2592eb948e50SMasami Hiramatsu tp->address = map->unmap_ip(map, sym->start) + pp->offset; 2593eb948e50SMasami Hiramatsu if (reloc_sym) { 2594eb948e50SMasami Hiramatsu tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out); 2595eb948e50SMasami Hiramatsu tp->offset = tp->address - reloc_sym->addr; 2596eb948e50SMasami Hiramatsu } else { 2597eb948e50SMasami Hiramatsu tp->symbol = strdup_or_goto(sym->name, nomem_out); 2598eb948e50SMasami Hiramatsu tp->offset = pp->offset; 2599eb948e50SMasami Hiramatsu } 2600eb948e50SMasami Hiramatsu tp->retprobe = pp->retprobe; 260144225521SMasami Hiramatsu if (pev->target) 260244225521SMasami Hiramatsu tev->point.module = strdup_or_goto(pev->target, 260344225521SMasami Hiramatsu nomem_out); 2604eb948e50SMasami Hiramatsu tev->uprobes = pev->uprobes; 2605eb948e50SMasami Hiramatsu tev->nargs = pev->nargs; 2606eb948e50SMasami Hiramatsu if (tev->nargs) { 2607eb948e50SMasami Hiramatsu tev->args = zalloc(sizeof(struct probe_trace_arg) * 2608eb948e50SMasami Hiramatsu tev->nargs); 2609eb948e50SMasami Hiramatsu if (tev->args == NULL) 2610eb948e50SMasami Hiramatsu goto nomem_out; 2611eb948e50SMasami Hiramatsu } 2612eb948e50SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 2613eb948e50SMasami Hiramatsu if (pev->args[i].name) 2614eb948e50SMasami Hiramatsu tev->args[i].name = 2615eb948e50SMasami Hiramatsu strdup_or_goto(pev->args[i].name, 2616eb948e50SMasami Hiramatsu nomem_out); 2617eb948e50SMasami Hiramatsu 2618eb948e50SMasami Hiramatsu tev->args[i].value = strdup_or_goto(pev->args[i].var, 2619eb948e50SMasami Hiramatsu nomem_out); 2620eb948e50SMasami Hiramatsu if (pev->args[i].type) 2621eb948e50SMasami Hiramatsu tev->args[i].type = 2622eb948e50SMasami Hiramatsu strdup_or_goto(pev->args[i].type, 2623eb948e50SMasami Hiramatsu nomem_out); 2624eb948e50SMasami Hiramatsu } 26257b6ff0bdSNaveen N. Rao arch__fix_tev_from_maps(pev, tev, map); 2626eb948e50SMasami Hiramatsu } 2627eb948e50SMasami Hiramatsu 2628eb948e50SMasami Hiramatsu out: 26299b118acaSMasami Hiramatsu put_target_map(map, pev->uprobes); 2630eb948e50SMasami Hiramatsu return ret; 2631eb948e50SMasami Hiramatsu 2632eb948e50SMasami Hiramatsu nomem_out: 2633eb948e50SMasami Hiramatsu ret = -ENOMEM; 2634eb948e50SMasami Hiramatsu err_out: 2635eb948e50SMasami Hiramatsu clear_probe_trace_events(*tevs, num_matched_functions); 2636eb948e50SMasami Hiramatsu zfree(tevs); 2637eb948e50SMasami Hiramatsu goto out; 2638eb948e50SMasami Hiramatsu } 2639eb948e50SMasami Hiramatsu 2640d5c2e2c1SNaveen N. Rao bool __weak arch__prefers_symtab(void) { return false; } 2641d5c2e2c1SNaveen N. Rao 26420e60836bSSrikar Dronamraju static int convert_to_probe_trace_events(struct perf_probe_event *pev, 2643ddb2f58fSMasami Hiramatsu struct probe_trace_event **tevs) 2644e0faa8d3SMasami Hiramatsu { 2645eb948e50SMasami Hiramatsu int ret; 26464235b045SMasami Hiramatsu 2647fb7345bbSMasami Hiramatsu if (pev->uprobes && !pev->group) { 2648fb7345bbSMasami Hiramatsu /* Replace group name if not given */ 264944225521SMasami Hiramatsu ret = convert_exec_to_group(pev->target, &pev->group); 2650fb7345bbSMasami Hiramatsu if (ret != 0) { 2651fb7345bbSMasami Hiramatsu pr_warning("Failed to make a group name.\n"); 2652fb7345bbSMasami Hiramatsu return ret; 2653fb7345bbSMasami Hiramatsu } 2654fb7345bbSMasami Hiramatsu } 2655fb7345bbSMasami Hiramatsu 2656d5c2e2c1SNaveen N. Rao if (arch__prefers_symtab() && !perf_probe_event_need_dwarf(pev)) { 2657ddb2f58fSMasami Hiramatsu ret = find_probe_trace_events_from_map(pev, tevs); 2658d5c2e2c1SNaveen N. Rao if (ret > 0) 2659d5c2e2c1SNaveen N. Rao return ret; /* Found in symbol table */ 2660d5c2e2c1SNaveen N. Rao } 2661d5c2e2c1SNaveen N. Rao 26624b4da7f7SMasami Hiramatsu /* Convert perf_probe_event with debuginfo */ 2663ddb2f58fSMasami Hiramatsu ret = try_to_find_probe_trace_events(pev, tevs); 2664e334016fSMasami Hiramatsu if (ret != 0) 2665190b57fcSMasami Hiramatsu return ret; /* Found in debuginfo or got an error */ 2666e0faa8d3SMasami Hiramatsu 2667ddb2f58fSMasami Hiramatsu return find_probe_trace_events_from_map(pev, tevs); 26684235b045SMasami Hiramatsu } 26694235b045SMasami Hiramatsu 26704235b045SMasami Hiramatsu struct __event_package { 26714235b045SMasami Hiramatsu struct perf_probe_event *pev; 26720e60836bSSrikar Dronamraju struct probe_trace_event *tevs; 26734235b045SMasami Hiramatsu int ntevs; 26744235b045SMasami Hiramatsu }; 26754235b045SMasami Hiramatsu 2676ddb2f58fSMasami Hiramatsu int add_perf_probe_events(struct perf_probe_event *pevs, int npevs) 26774235b045SMasami Hiramatsu { 2678146a1439SMasami Hiramatsu int i, j, ret; 26794235b045SMasami Hiramatsu struct __event_package *pkgs; 26804235b045SMasami Hiramatsu 2681225466f1SSrikar Dronamraju ret = 0; 2682e334016fSMasami Hiramatsu pkgs = zalloc(sizeof(struct __event_package) * npevs); 2683225466f1SSrikar Dronamraju 2684e334016fSMasami Hiramatsu if (pkgs == NULL) 2685e334016fSMasami Hiramatsu return -ENOMEM; 26864235b045SMasami Hiramatsu 2687ee45b6c2SMasami Hiramatsu ret = init_symbol_maps(pevs->uprobes); 2688449e5b24SMasami Hiramatsu if (ret < 0) { 2689449e5b24SMasami Hiramatsu free(pkgs); 2690146a1439SMasami Hiramatsu return ret; 2691449e5b24SMasami Hiramatsu } 26924235b045SMasami Hiramatsu 26934235b045SMasami Hiramatsu /* Loop 1: convert all events */ 26944235b045SMasami Hiramatsu for (i = 0; i < npevs; i++) { 26954235b045SMasami Hiramatsu pkgs[i].pev = &pevs[i]; 26964235b045SMasami Hiramatsu /* Convert with or without debuginfo */ 26970e60836bSSrikar Dronamraju ret = convert_to_probe_trace_events(pkgs[i].pev, 2698ddb2f58fSMasami Hiramatsu &pkgs[i].tevs); 2699146a1439SMasami Hiramatsu if (ret < 0) 2700146a1439SMasami Hiramatsu goto end; 2701146a1439SMasami Hiramatsu pkgs[i].ntevs = ret; 27024235b045SMasami Hiramatsu } 27034235b045SMasami Hiramatsu 27044235b045SMasami Hiramatsu /* Loop 2: add all events */ 27058635bf6eSArnaldo Carvalho de Melo for (i = 0; i < npevs; i++) { 27060e60836bSSrikar Dronamraju ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, 2707ddb2f58fSMasami Hiramatsu pkgs[i].ntevs, 2708ddb2f58fSMasami Hiramatsu probe_conf.force_add); 2709fbee632dSArnaldo Carvalho de Melo if (ret < 0) 2710fbee632dSArnaldo Carvalho de Melo break; 2711fbee632dSArnaldo Carvalho de Melo } 2712146a1439SMasami Hiramatsu end: 2713449e5b24SMasami Hiramatsu /* Loop 3: cleanup and free trace events */ 2714449e5b24SMasami Hiramatsu for (i = 0; i < npevs; i++) { 2715146a1439SMasami Hiramatsu for (j = 0; j < pkgs[i].ntevs; j++) 27160e60836bSSrikar Dronamraju clear_probe_trace_event(&pkgs[i].tevs[j]); 271774cf249dSArnaldo Carvalho de Melo zfree(&pkgs[i].tevs); 2718449e5b24SMasami Hiramatsu } 2719449e5b24SMasami Hiramatsu free(pkgs); 2720ee45b6c2SMasami Hiramatsu exit_symbol_maps(); 2721146a1439SMasami Hiramatsu 2722146a1439SMasami Hiramatsu return ret; 2723e0faa8d3SMasami Hiramatsu } 2724e0faa8d3SMasami Hiramatsu 27250e60836bSSrikar Dronamraju static int __del_trace_probe_event(int fd, struct str_node *ent) 2726bbbb521bSMasami Hiramatsu { 2727bbbb521bSMasami Hiramatsu char *p; 2728bbbb521bSMasami Hiramatsu char buf[128]; 27294235b045SMasami Hiramatsu int ret; 2730bbbb521bSMasami Hiramatsu 27310e60836bSSrikar Dronamraju /* Convert from perf-probe event to trace-probe event */ 2732146a1439SMasami Hiramatsu ret = e_snprintf(buf, 128, "-:%s", ent->s); 2733146a1439SMasami Hiramatsu if (ret < 0) 2734146a1439SMasami Hiramatsu goto error; 2735146a1439SMasami Hiramatsu 2736bbbb521bSMasami Hiramatsu p = strchr(buf + 2, ':'); 2737146a1439SMasami Hiramatsu if (!p) { 2738146a1439SMasami Hiramatsu pr_debug("Internal error: %s should have ':' but not.\n", 2739146a1439SMasami Hiramatsu ent->s); 2740146a1439SMasami Hiramatsu ret = -ENOTSUP; 2741146a1439SMasami Hiramatsu goto error; 2742146a1439SMasami Hiramatsu } 2743bbbb521bSMasami Hiramatsu *p = '/'; 2744bbbb521bSMasami Hiramatsu 27454235b045SMasami Hiramatsu pr_debug("Writing event: %s\n", buf); 27464235b045SMasami Hiramatsu ret = write(fd, buf, strlen(buf)); 274744a56040SMasami Hiramatsu if (ret < 0) { 274844a56040SMasami Hiramatsu ret = -errno; 2749146a1439SMasami Hiramatsu goto error; 275044a56040SMasami Hiramatsu } 2751146a1439SMasami Hiramatsu 27525e17b28fSMasami Hiramatsu pr_info("Removed event: %s\n", ent->s); 2753146a1439SMasami Hiramatsu return 0; 2754146a1439SMasami Hiramatsu error: 27555f03cba4SMasami Hiramatsu pr_warning("Failed to delete event: %s\n", 27565f03cba4SMasami Hiramatsu strerror_r(-ret, buf, sizeof(buf))); 2757146a1439SMasami Hiramatsu return ret; 2758bbbb521bSMasami Hiramatsu } 2759bbbb521bSMasami Hiramatsu 2760307a464bSMasami Hiramatsu static int del_trace_probe_events(int fd, struct strfilter *filter, 2761225466f1SSrikar Dronamraju struct strlist *namelist) 2762fa28244dSMasami Hiramatsu { 2763307a464bSMasami Hiramatsu struct str_node *ent; 2764307a464bSMasami Hiramatsu const char *p; 27656dbe31f7SMasami Hiramatsu int ret = -ENOENT; 2766fa28244dSMasami Hiramatsu 2767307a464bSMasami Hiramatsu if (!namelist) 2768307a464bSMasami Hiramatsu return -ENOENT; 2769307a464bSMasami Hiramatsu 2770307a464bSMasami Hiramatsu strlist__for_each(ent, namelist) { 2771307a464bSMasami Hiramatsu p = strchr(ent->s, ':'); 2772307a464bSMasami Hiramatsu if ((p && strfilter__compare(filter, p + 1)) || 2773307a464bSMasami Hiramatsu strfilter__compare(filter, ent->s)) { 27740e60836bSSrikar Dronamraju ret = __del_trace_probe_event(fd, ent); 2775146a1439SMasami Hiramatsu if (ret < 0) 2776146a1439SMasami Hiramatsu break; 2777bbbb521bSMasami Hiramatsu } 2778bbbb521bSMasami Hiramatsu } 2779146a1439SMasami Hiramatsu 2780146a1439SMasami Hiramatsu return ret; 2781bbbb521bSMasami Hiramatsu } 2782fa28244dSMasami Hiramatsu 2783307a464bSMasami Hiramatsu int del_perf_probe_events(struct strfilter *filter) 2784fa28244dSMasami Hiramatsu { 2785307a464bSMasami Hiramatsu int ret, ret2, ufd = -1, kfd = -1; 2786225466f1SSrikar Dronamraju struct strlist *namelist = NULL, *unamelist = NULL; 2787307a464bSMasami Hiramatsu char *str = strfilter__string(filter); 2788307a464bSMasami Hiramatsu 2789307a464bSMasami Hiramatsu if (!str) 2790307a464bSMasami Hiramatsu return -EINVAL; 2791307a464bSMasami Hiramatsu 2792307a464bSMasami Hiramatsu pr_debug("Delete filter: \'%s\'\n", str); 2793146a1439SMasami Hiramatsu 2794fa28244dSMasami Hiramatsu /* Get current event names */ 2795225466f1SSrikar Dronamraju kfd = open_kprobe_events(true); 2796467ec085SMasami Hiramatsu if (kfd >= 0) 2797225466f1SSrikar Dronamraju namelist = get_probe_trace_event_names(kfd, true); 2798225466f1SSrikar Dronamraju 2799467ec085SMasami Hiramatsu ufd = open_uprobe_events(true); 2800467ec085SMasami Hiramatsu if (ufd >= 0) 2801225466f1SSrikar Dronamraju unamelist = get_probe_trace_event_names(ufd, true); 2802225466f1SSrikar Dronamraju 2803467ec085SMasami Hiramatsu if (kfd < 0 && ufd < 0) { 2804467ec085SMasami Hiramatsu print_both_open_warning(kfd, ufd); 2805307a464bSMasami Hiramatsu ret = kfd; 2806467ec085SMasami Hiramatsu goto error; 2807467ec085SMasami Hiramatsu } 2808467ec085SMasami Hiramatsu 2809307a464bSMasami Hiramatsu ret = del_trace_probe_events(kfd, filter, namelist); 2810307a464bSMasami Hiramatsu if (ret < 0 && ret != -ENOENT) 2811225466f1SSrikar Dronamraju goto error; 2812fa28244dSMasami Hiramatsu 2813307a464bSMasami Hiramatsu ret2 = del_trace_probe_events(ufd, filter, unamelist); 2814dddc7ee3SMasami Hiramatsu if (ret2 < 0 && ret2 != -ENOENT) { 28156dbe31f7SMasami Hiramatsu ret = ret2; 2816dddc7ee3SMasami Hiramatsu goto error; 2817dddc7ee3SMasami Hiramatsu } 2818dddc7ee3SMasami Hiramatsu if (ret == -ENOENT && ret2 == -ENOENT) 2819307a464bSMasami Hiramatsu pr_debug("\"%s\" does not hit any event.\n", str); 2820307a464bSMasami Hiramatsu /* Note that this is silently ignored */ 2821307a464bSMasami Hiramatsu ret = 0; 2822225466f1SSrikar Dronamraju 2823225466f1SSrikar Dronamraju error: 2824225466f1SSrikar Dronamraju if (kfd >= 0) { 2825fa28244dSMasami Hiramatsu strlist__delete(namelist); 2826225466f1SSrikar Dronamraju close(kfd); 2827225466f1SSrikar Dronamraju } 2828225466f1SSrikar Dronamraju 2829225466f1SSrikar Dronamraju if (ufd >= 0) { 2830225466f1SSrikar Dronamraju strlist__delete(unamelist); 2831225466f1SSrikar Dronamraju close(ufd); 2832225466f1SSrikar Dronamraju } 2833307a464bSMasami Hiramatsu free(str); 2834146a1439SMasami Hiramatsu 2835146a1439SMasami Hiramatsu return ret; 2836fa28244dSMasami Hiramatsu } 2837225466f1SSrikar Dronamraju 28383c42258cSMasami Hiramatsu /* TODO: don't use a global variable for filter ... */ 28393c42258cSMasami Hiramatsu static struct strfilter *available_func_filter; 2840fa28244dSMasami Hiramatsu 2841e80711caSMasami Hiramatsu /* 28423c42258cSMasami Hiramatsu * If a symbol corresponds to a function with global binding and 28433c42258cSMasami Hiramatsu * matches filter return 0. For all others return 1. 2844e80711caSMasami Hiramatsu */ 28451d037ca1SIrina Tirdea static int filter_available_functions(struct map *map __maybe_unused, 2846e80711caSMasami Hiramatsu struct symbol *sym) 2847e80711caSMasami Hiramatsu { 2848e578da3bSNamhyung Kim if (strfilter__compare(available_func_filter, sym->name)) 2849e80711caSMasami Hiramatsu return 0; 28503c42258cSMasami Hiramatsu return 1; 2851e80711caSMasami Hiramatsu } 2852e80711caSMasami Hiramatsu 28532df58634SMasami Hiramatsu int show_available_funcs(const char *target, struct strfilter *_filter, 28542df58634SMasami Hiramatsu bool user) 2855e80711caSMasami Hiramatsu { 28562df58634SMasami Hiramatsu struct map *map; 28572df58634SMasami Hiramatsu int ret; 28582df58634SMasami Hiramatsu 28592df58634SMasami Hiramatsu ret = init_symbol_maps(user); 28602df58634SMasami Hiramatsu if (ret < 0) 28612df58634SMasami Hiramatsu return ret; 28622df58634SMasami Hiramatsu 28632df58634SMasami Hiramatsu /* Get a symbol map */ 28642df58634SMasami Hiramatsu if (user) 28652df58634SMasami Hiramatsu map = dso__new_map(target); 28662df58634SMasami Hiramatsu else 28672df58634SMasami Hiramatsu map = kernel_get_module_map(target); 28682df58634SMasami Hiramatsu if (!map) { 28692df58634SMasami Hiramatsu pr_err("Failed to get a map for %s\n", (target) ? : "kernel"); 2870e80711caSMasami Hiramatsu return -EINVAL; 2871e80711caSMasami Hiramatsu } 28722df58634SMasami Hiramatsu 28732df58634SMasami Hiramatsu /* Load symbols with given filter */ 28742df58634SMasami Hiramatsu available_func_filter = _filter; 28752df58634SMasami Hiramatsu if (map__load(map, filter_available_functions)) { 28762df58634SMasami Hiramatsu pr_err("Failed to load symbols in %s\n", (target) ? : "kernel"); 28772df58634SMasami Hiramatsu goto end; 28782df58634SMasami Hiramatsu } 2879e80711caSMasami Hiramatsu if (!dso__sorted_by_name(map->dso, map->type)) 2880e80711caSMasami Hiramatsu dso__sort_by_name(map->dso, map->type); 2881e80711caSMasami Hiramatsu 28822df58634SMasami Hiramatsu /* Show all (filtered) symbols */ 28832df58634SMasami Hiramatsu setup_pager(); 2884e80711caSMasami Hiramatsu dso__fprintf_symbols_by_name(map->dso, map->type, stdout); 28852df58634SMasami Hiramatsu end: 28862df58634SMasami Hiramatsu if (user) { 2887225466f1SSrikar Dronamraju map__delete(map); 2888225466f1SSrikar Dronamraju } 28892df58634SMasami Hiramatsu exit_symbol_maps(); 2890225466f1SSrikar Dronamraju 28912df58634SMasami Hiramatsu return ret; 2892225466f1SSrikar Dronamraju } 2893225466f1SSrikar Dronamraju 2894