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 */ 54f4d7da49SMasami Hiramatsu 55146a1439SMasami Hiramatsu #define semantic_error(msg ...) pr_err("Semantic error :" msg) 5650656eecSMasami Hiramatsu 574de189feSMasami Hiramatsu /* If there is no space to write, returns -E2BIG. */ 584de189feSMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...) 5984988450SMasami Hiramatsu __attribute__((format(printf, 3, 4))); 6084988450SMasami Hiramatsu 6184988450SMasami Hiramatsu static int e_snprintf(char *str, size_t size, const char *format, ...) 624de189feSMasami Hiramatsu { 634de189feSMasami Hiramatsu int ret; 644de189feSMasami Hiramatsu va_list ap; 654de189feSMasami Hiramatsu va_start(ap, format); 664de189feSMasami Hiramatsu ret = vsnprintf(str, size, format, ap); 674de189feSMasami Hiramatsu va_end(ap); 684de189feSMasami Hiramatsu if (ret >= (int)size) 694de189feSMasami Hiramatsu ret = -E2BIG; 704de189feSMasami Hiramatsu return ret; 714de189feSMasami Hiramatsu } 724de189feSMasami Hiramatsu 734b4da7f7SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 74981d05adSMasami Hiramatsu static void clear_probe_trace_event(struct probe_trace_event *tev); 75ee45b6c2SMasami Hiramatsu static struct machine *host_machine; 76e0faa8d3SMasami Hiramatsu 77469b9b88SMasami Hiramatsu /* Initialize symbol maps and path of vmlinux/modules */ 78ee45b6c2SMasami Hiramatsu static int init_symbol_maps(bool user_only) 79e0faa8d3SMasami Hiramatsu { 80146a1439SMasami Hiramatsu int ret; 81146a1439SMasami Hiramatsu 82e0faa8d3SMasami Hiramatsu symbol_conf.sort_by_name = true; 830a7e6d1bSNamhyung Kim ret = symbol__init(NULL); 84146a1439SMasami Hiramatsu if (ret < 0) { 85146a1439SMasami Hiramatsu pr_debug("Failed to init symbol map.\n"); 86146a1439SMasami Hiramatsu goto out; 87146a1439SMasami Hiramatsu } 88e0faa8d3SMasami Hiramatsu 89ee45b6c2SMasami Hiramatsu if (host_machine || user_only) /* already initialized */ 90ee45b6c2SMasami Hiramatsu return 0; 91d28c6223SArnaldo Carvalho de Melo 92ee45b6c2SMasami Hiramatsu if (symbol_conf.vmlinux_name) 93ee45b6c2SMasami Hiramatsu pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name); 94ee45b6c2SMasami Hiramatsu 95ee45b6c2SMasami Hiramatsu host_machine = machine__new_host(); 96ee45b6c2SMasami Hiramatsu if (!host_machine) { 97ee45b6c2SMasami Hiramatsu pr_debug("machine__new_host() failed.\n"); 98ee45b6c2SMasami Hiramatsu symbol__exit(); 99ee45b6c2SMasami Hiramatsu ret = -1; 100469b9b88SMasami Hiramatsu } 101146a1439SMasami Hiramatsu out: 102146a1439SMasami Hiramatsu if (ret < 0) 103146a1439SMasami Hiramatsu pr_warning("Failed to init vmlinux path.\n"); 104146a1439SMasami Hiramatsu return ret; 105e0faa8d3SMasami Hiramatsu } 106e0faa8d3SMasami Hiramatsu 107ee45b6c2SMasami Hiramatsu static void exit_symbol_maps(void) 108ee45b6c2SMasami Hiramatsu { 109ee45b6c2SMasami Hiramatsu if (host_machine) { 110ee45b6c2SMasami Hiramatsu machine__delete(host_machine); 111ee45b6c2SMasami Hiramatsu host_machine = NULL; 112ee45b6c2SMasami Hiramatsu } 113ee45b6c2SMasami Hiramatsu symbol__exit(); 114ee45b6c2SMasami Hiramatsu } 115ee45b6c2SMasami Hiramatsu 116469b9b88SMasami Hiramatsu static struct symbol *__find_kernel_function_by_name(const char *name, 117469b9b88SMasami Hiramatsu struct map **mapp) 118e0faa8d3SMasami Hiramatsu { 119ee45b6c2SMasami Hiramatsu return machine__find_kernel_function_by_name(host_machine, name, mapp, 120469b9b88SMasami Hiramatsu NULL); 121e0faa8d3SMasami Hiramatsu } 122469b9b88SMasami Hiramatsu 1238f33f7deSMasami Hiramatsu static struct symbol *__find_kernel_function(u64 addr, struct map **mapp) 1248f33f7deSMasami Hiramatsu { 1258f33f7deSMasami Hiramatsu return machine__find_kernel_function(host_machine, addr, mapp, NULL); 1268f33f7deSMasami Hiramatsu } 1278f33f7deSMasami Hiramatsu 1288f33f7deSMasami Hiramatsu static struct ref_reloc_sym *kernel_get_ref_reloc_sym(void) 1298f33f7deSMasami Hiramatsu { 1308f33f7deSMasami Hiramatsu /* kmap->ref_reloc_sym should be set if host_machine is initialized */ 1318f33f7deSMasami Hiramatsu struct kmap *kmap; 1328f33f7deSMasami Hiramatsu 1338f33f7deSMasami Hiramatsu if (map__load(host_machine->vmlinux_maps[MAP__FUNCTION], NULL) < 0) 1348f33f7deSMasami Hiramatsu return NULL; 1358f33f7deSMasami Hiramatsu 1368f33f7deSMasami Hiramatsu kmap = map__kmap(host_machine->vmlinux_maps[MAP__FUNCTION]); 1378f33f7deSMasami Hiramatsu return kmap->ref_reloc_sym; 1388f33f7deSMasami Hiramatsu } 1398f33f7deSMasami Hiramatsu 1408f33f7deSMasami Hiramatsu static u64 kernel_get_symbol_address_by_name(const char *name, bool reloc) 1418f33f7deSMasami Hiramatsu { 1428f33f7deSMasami Hiramatsu struct ref_reloc_sym *reloc_sym; 1438f33f7deSMasami Hiramatsu struct symbol *sym; 1448f33f7deSMasami Hiramatsu struct map *map; 1458f33f7deSMasami Hiramatsu 1468f33f7deSMasami Hiramatsu /* ref_reloc_sym is just a label. Need a special fix*/ 1478f33f7deSMasami Hiramatsu reloc_sym = kernel_get_ref_reloc_sym(); 1488f33f7deSMasami Hiramatsu if (reloc_sym && strcmp(name, reloc_sym->name) == 0) 1498f33f7deSMasami Hiramatsu return (reloc) ? reloc_sym->addr : reloc_sym->unrelocated_addr; 1508f33f7deSMasami Hiramatsu else { 1518f33f7deSMasami Hiramatsu sym = __find_kernel_function_by_name(name, &map); 1528f33f7deSMasami Hiramatsu if (sym) 1538f33f7deSMasami Hiramatsu return map->unmap_ip(map, sym->start) - 154f56847c2SHe Kuang ((reloc) ? 0 : map->reloc); 1558f33f7deSMasami Hiramatsu } 1568f33f7deSMasami Hiramatsu return 0; 1578f33f7deSMasami Hiramatsu } 1588f33f7deSMasami Hiramatsu 159e80711caSMasami Hiramatsu static struct map *kernel_get_module_map(const char *module) 160e80711caSMasami Hiramatsu { 161e80711caSMasami Hiramatsu struct rb_node *nd; 162ee45b6c2SMasami Hiramatsu struct map_groups *grp = &host_machine->kmaps; 163e80711caSMasami Hiramatsu 16414a8fd7cSMasami Hiramatsu /* A file path -- this is an offline module */ 16514a8fd7cSMasami Hiramatsu if (module && strchr(module, '/')) 166ee45b6c2SMasami Hiramatsu return machine__new_module(host_machine, 0, module); 16714a8fd7cSMasami Hiramatsu 168e80711caSMasami Hiramatsu if (!module) 169e80711caSMasami Hiramatsu module = "kernel"; 170e80711caSMasami Hiramatsu 171e80711caSMasami Hiramatsu for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { 172e80711caSMasami Hiramatsu struct map *pos = rb_entry(nd, struct map, rb_node); 173e80711caSMasami Hiramatsu if (strncmp(pos->dso->short_name + 1, module, 174e80711caSMasami Hiramatsu pos->dso->short_name_len - 2) == 0) { 175e80711caSMasami Hiramatsu return pos; 176e80711caSMasami Hiramatsu } 177e80711caSMasami Hiramatsu } 178e80711caSMasami Hiramatsu return NULL; 179e80711caSMasami Hiramatsu } 180e80711caSMasami Hiramatsu 181*9b118acaSMasami Hiramatsu static struct map *get_target_map(const char *target, bool user) 182*9b118acaSMasami Hiramatsu { 183*9b118acaSMasami Hiramatsu /* Init maps of given executable or kernel */ 184*9b118acaSMasami Hiramatsu if (user) 185*9b118acaSMasami Hiramatsu return dso__new_map(target); 186*9b118acaSMasami Hiramatsu else 187*9b118acaSMasami Hiramatsu return kernel_get_module_map(target); 188*9b118acaSMasami Hiramatsu } 189*9b118acaSMasami Hiramatsu 190*9b118acaSMasami Hiramatsu static void put_target_map(struct map *map, bool user) 191*9b118acaSMasami Hiramatsu { 192*9b118acaSMasami Hiramatsu if (map && user) { 193*9b118acaSMasami Hiramatsu /* Only the user map needs to be released */ 194*9b118acaSMasami Hiramatsu dso__delete(map->dso); 195*9b118acaSMasami Hiramatsu map__delete(map); 196*9b118acaSMasami Hiramatsu } 197*9b118acaSMasami Hiramatsu } 198*9b118acaSMasami Hiramatsu 199*9b118acaSMasami Hiramatsu 200e80711caSMasami Hiramatsu static struct dso *kernel_get_module_dso(const char *module) 201469b9b88SMasami Hiramatsu { 202469b9b88SMasami Hiramatsu struct dso *dso; 203fd930ff9SFranck Bui-Huu struct map *map; 204fd930ff9SFranck Bui-Huu const char *vmlinux_name; 205469b9b88SMasami Hiramatsu 206469b9b88SMasami Hiramatsu if (module) { 2078fa7d87fSWaiman Long list_for_each_entry(dso, &host_machine->kernel_dsos.head, 2088fa7d87fSWaiman Long node) { 209469b9b88SMasami Hiramatsu if (strncmp(dso->short_name + 1, module, 210469b9b88SMasami Hiramatsu dso->short_name_len - 2) == 0) 211469b9b88SMasami Hiramatsu goto found; 212469b9b88SMasami Hiramatsu } 213469b9b88SMasami Hiramatsu pr_debug("Failed to find module %s.\n", module); 214469b9b88SMasami Hiramatsu return NULL; 215fd930ff9SFranck Bui-Huu } 216fd930ff9SFranck Bui-Huu 217ee45b6c2SMasami Hiramatsu map = host_machine->vmlinux_maps[MAP__FUNCTION]; 218fd930ff9SFranck Bui-Huu dso = map->dso; 219fd930ff9SFranck Bui-Huu 220fd930ff9SFranck Bui-Huu vmlinux_name = symbol_conf.vmlinux_name; 221fd930ff9SFranck Bui-Huu if (vmlinux_name) { 2225230fb7dSArnaldo Carvalho de Melo if (dso__load_vmlinux(dso, map, vmlinux_name, false, NULL) <= 0) 223fd930ff9SFranck Bui-Huu return NULL; 224469b9b88SMasami Hiramatsu } else { 225c3a34e06SFranck Bui-Huu if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { 226469b9b88SMasami Hiramatsu pr_debug("Failed to load kernel map.\n"); 227469b9b88SMasami Hiramatsu return NULL; 228469b9b88SMasami Hiramatsu } 229469b9b88SMasami Hiramatsu } 230469b9b88SMasami Hiramatsu found: 231e80711caSMasami Hiramatsu return dso; 232e80711caSMasami Hiramatsu } 233e80711caSMasami Hiramatsu 234e80711caSMasami Hiramatsu const char *kernel_get_module_path(const char *module) 235e80711caSMasami Hiramatsu { 236e80711caSMasami Hiramatsu struct dso *dso = kernel_get_module_dso(module); 237e80711caSMasami Hiramatsu return (dso) ? dso->long_name : NULL; 238469b9b88SMasami Hiramatsu } 239469b9b88SMasami Hiramatsu 240fb7345bbSMasami Hiramatsu static int convert_exec_to_group(const char *exec, char **result) 241fb7345bbSMasami Hiramatsu { 242fb7345bbSMasami Hiramatsu char *ptr1, *ptr2, *exec_copy; 243fb7345bbSMasami Hiramatsu char buf[64]; 244fb7345bbSMasami Hiramatsu int ret; 245fb7345bbSMasami Hiramatsu 246fb7345bbSMasami Hiramatsu exec_copy = strdup(exec); 247fb7345bbSMasami Hiramatsu if (!exec_copy) 248fb7345bbSMasami Hiramatsu return -ENOMEM; 249fb7345bbSMasami Hiramatsu 250fb7345bbSMasami Hiramatsu ptr1 = basename(exec_copy); 251fb7345bbSMasami Hiramatsu if (!ptr1) { 252fb7345bbSMasami Hiramatsu ret = -EINVAL; 253fb7345bbSMasami Hiramatsu goto out; 254fb7345bbSMasami Hiramatsu } 255fb7345bbSMasami Hiramatsu 256fb7345bbSMasami Hiramatsu ptr2 = strpbrk(ptr1, "-._"); 257fb7345bbSMasami Hiramatsu if (ptr2) 258fb7345bbSMasami Hiramatsu *ptr2 = '\0'; 259fb7345bbSMasami Hiramatsu ret = e_snprintf(buf, 64, "%s_%s", PERFPROBE_GROUP, ptr1); 260fb7345bbSMasami Hiramatsu if (ret < 0) 261fb7345bbSMasami Hiramatsu goto out; 262fb7345bbSMasami Hiramatsu 263fb7345bbSMasami Hiramatsu *result = strdup(buf); 264fb7345bbSMasami Hiramatsu ret = *result ? 0 : -ENOMEM; 265fb7345bbSMasami Hiramatsu 266fb7345bbSMasami Hiramatsu out: 267fb7345bbSMasami Hiramatsu free(exec_copy); 268fb7345bbSMasami Hiramatsu return ret; 269fb7345bbSMasami Hiramatsu } 270fb7345bbSMasami Hiramatsu 271*9b118acaSMasami Hiramatsu static void clear_perf_probe_point(struct perf_probe_point *pp) 272*9b118acaSMasami Hiramatsu { 273*9b118acaSMasami Hiramatsu free(pp->file); 274*9b118acaSMasami Hiramatsu free(pp->function); 275*9b118acaSMasami Hiramatsu free(pp->lazy_line); 276*9b118acaSMasami Hiramatsu } 277*9b118acaSMasami Hiramatsu 278eb948e50SMasami Hiramatsu static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) 279eb948e50SMasami Hiramatsu { 280eb948e50SMasami Hiramatsu int i; 281eb948e50SMasami Hiramatsu 282eb948e50SMasami Hiramatsu for (i = 0; i < ntevs; i++) 283eb948e50SMasami Hiramatsu clear_probe_trace_event(tevs + i); 284eb948e50SMasami Hiramatsu } 285eb948e50SMasami Hiramatsu 28689fe808aSIngo Molnar #ifdef HAVE_DWARF_SUPPORT 287*9b118acaSMasami Hiramatsu /* 288*9b118acaSMasami Hiramatsu * Some binaries like glibc have special symbols which are on the symbol 289*9b118acaSMasami Hiramatsu * table, but not in the debuginfo. If we can find the address of the 290*9b118acaSMasami Hiramatsu * symbol from map, we can translate the address back to the probe point. 291*9b118acaSMasami Hiramatsu */ 292*9b118acaSMasami Hiramatsu static int find_alternative_probe_point(struct debuginfo *dinfo, 293*9b118acaSMasami Hiramatsu struct perf_probe_point *pp, 294*9b118acaSMasami Hiramatsu struct perf_probe_point *result, 295*9b118acaSMasami Hiramatsu const char *target, bool uprobes) 296*9b118acaSMasami Hiramatsu { 297*9b118acaSMasami Hiramatsu struct map *map = NULL; 298*9b118acaSMasami Hiramatsu struct symbol *sym; 299*9b118acaSMasami Hiramatsu u64 address = 0; 300*9b118acaSMasami Hiramatsu int ret = -ENOENT; 301*9b118acaSMasami Hiramatsu 302*9b118acaSMasami Hiramatsu /* This can work only for function-name based one */ 303*9b118acaSMasami Hiramatsu if (!pp->function || pp->file) 304*9b118acaSMasami Hiramatsu return -ENOTSUP; 305*9b118acaSMasami Hiramatsu 306*9b118acaSMasami Hiramatsu map = get_target_map(target, uprobes); 307*9b118acaSMasami Hiramatsu if (!map) 308*9b118acaSMasami Hiramatsu return -EINVAL; 309*9b118acaSMasami Hiramatsu 310*9b118acaSMasami Hiramatsu /* Find the address of given function */ 311*9b118acaSMasami Hiramatsu map__for_each_symbol_by_name(map, pp->function, sym) { 312*9b118acaSMasami Hiramatsu if (sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) { 313*9b118acaSMasami Hiramatsu address = sym->start; 314*9b118acaSMasami Hiramatsu break; 315*9b118acaSMasami Hiramatsu } 316*9b118acaSMasami Hiramatsu } 317*9b118acaSMasami Hiramatsu if (!address) { 318*9b118acaSMasami Hiramatsu ret = -ENOENT; 319*9b118acaSMasami Hiramatsu goto out; 320*9b118acaSMasami Hiramatsu } 321*9b118acaSMasami Hiramatsu pr_debug("Symbol %s address found : %lx\n", pp->function, address); 322*9b118acaSMasami Hiramatsu 323*9b118acaSMasami Hiramatsu ret = debuginfo__find_probe_point(dinfo, (unsigned long)address, 324*9b118acaSMasami Hiramatsu result); 325*9b118acaSMasami Hiramatsu if (ret <= 0) 326*9b118acaSMasami Hiramatsu ret = (!ret) ? -ENOENT : ret; 327*9b118acaSMasami Hiramatsu else { 328*9b118acaSMasami Hiramatsu result->offset += pp->offset; 329*9b118acaSMasami Hiramatsu result->line += pp->line; 330*9b118acaSMasami Hiramatsu ret = 0; 331*9b118acaSMasami Hiramatsu } 332*9b118acaSMasami Hiramatsu 333*9b118acaSMasami Hiramatsu out: 334*9b118acaSMasami Hiramatsu put_target_map(map, uprobes); 335*9b118acaSMasami Hiramatsu return ret; 336*9b118acaSMasami Hiramatsu 337*9b118acaSMasami Hiramatsu } 338*9b118acaSMasami Hiramatsu 339*9b118acaSMasami Hiramatsu static int get_alternative_probe_event(struct debuginfo *dinfo, 340*9b118acaSMasami Hiramatsu struct perf_probe_event *pev, 341*9b118acaSMasami Hiramatsu struct perf_probe_point *tmp, 342*9b118acaSMasami Hiramatsu const char *target) 343*9b118acaSMasami Hiramatsu { 344*9b118acaSMasami Hiramatsu int ret; 345*9b118acaSMasami Hiramatsu 346*9b118acaSMasami Hiramatsu memcpy(tmp, &pev->point, sizeof(*tmp)); 347*9b118acaSMasami Hiramatsu memset(&pev->point, 0, sizeof(pev->point)); 348*9b118acaSMasami Hiramatsu ret = find_alternative_probe_point(dinfo, tmp, &pev->point, 349*9b118acaSMasami Hiramatsu target, pev->uprobes); 350*9b118acaSMasami Hiramatsu if (ret < 0) 351*9b118acaSMasami Hiramatsu memcpy(&pev->point, tmp, sizeof(*tmp)); 352*9b118acaSMasami Hiramatsu 353*9b118acaSMasami Hiramatsu return ret; 354*9b118acaSMasami Hiramatsu } 355a15ad2f5SMasami Hiramatsu 356ff741783SMasami Hiramatsu /* Open new debuginfo of given module */ 35792561cb7SMasami Hiramatsu static struct debuginfo *open_debuginfo(const char *module, bool silent) 358469b9b88SMasami Hiramatsu { 359a15ad2f5SMasami Hiramatsu const char *path = module; 36092561cb7SMasami Hiramatsu struct debuginfo *ret; 36114a8fd7cSMasami Hiramatsu 362a15ad2f5SMasami Hiramatsu if (!module || !strchr(module, '/')) { 36314a8fd7cSMasami Hiramatsu path = kernel_get_module_path(module); 364469b9b88SMasami Hiramatsu if (!path) { 36592561cb7SMasami Hiramatsu if (!silent) 3660e43e5d2SMasami Hiramatsu pr_err("Failed to find path of %s module.\n", 3670e43e5d2SMasami Hiramatsu module ?: "kernel"); 368ff741783SMasami Hiramatsu return NULL; 369469b9b88SMasami Hiramatsu } 37014a8fd7cSMasami Hiramatsu } 37192561cb7SMasami Hiramatsu ret = debuginfo__new(path); 37292561cb7SMasami Hiramatsu if (!ret && !silent) { 37392561cb7SMasami Hiramatsu pr_warning("The %s file has no debug information.\n", path); 37492561cb7SMasami Hiramatsu if (!module || !strtailcmp(path, ".ko")) 37592561cb7SMasami Hiramatsu pr_warning("Rebuild with CONFIG_DEBUG_INFO=y, "); 37692561cb7SMasami Hiramatsu else 37792561cb7SMasami Hiramatsu pr_warning("Rebuild with -g, "); 37892561cb7SMasami Hiramatsu pr_warning("or install an appropriate debuginfo package.\n"); 379e0faa8d3SMasami Hiramatsu } 38092561cb7SMasami Hiramatsu return ret; 38192561cb7SMasami Hiramatsu } 38292561cb7SMasami Hiramatsu 3834b4da7f7SMasami Hiramatsu 38499ca4233SMasami Hiramatsu static int get_text_start_address(const char *exec, unsigned long *address) 38599ca4233SMasami Hiramatsu { 38699ca4233SMasami Hiramatsu Elf *elf; 38799ca4233SMasami Hiramatsu GElf_Ehdr ehdr; 38899ca4233SMasami Hiramatsu GElf_Shdr shdr; 38999ca4233SMasami Hiramatsu int fd, ret = -ENOENT; 39099ca4233SMasami Hiramatsu 39199ca4233SMasami Hiramatsu fd = open(exec, O_RDONLY); 39299ca4233SMasami Hiramatsu if (fd < 0) 39399ca4233SMasami Hiramatsu return -errno; 39499ca4233SMasami Hiramatsu 39599ca4233SMasami Hiramatsu elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); 39699ca4233SMasami Hiramatsu if (elf == NULL) 39799ca4233SMasami Hiramatsu return -EINVAL; 39899ca4233SMasami Hiramatsu 39999ca4233SMasami Hiramatsu if (gelf_getehdr(elf, &ehdr) == NULL) 40099ca4233SMasami Hiramatsu goto out; 40199ca4233SMasami Hiramatsu 40299ca4233SMasami Hiramatsu if (!elf_section_by_name(elf, &ehdr, &shdr, ".text", NULL)) 40399ca4233SMasami Hiramatsu goto out; 40499ca4233SMasami Hiramatsu 40599ca4233SMasami Hiramatsu *address = shdr.sh_addr - shdr.sh_offset; 40699ca4233SMasami Hiramatsu ret = 0; 40799ca4233SMasami Hiramatsu out: 40899ca4233SMasami Hiramatsu elf_end(elf); 40999ca4233SMasami Hiramatsu return ret; 41099ca4233SMasami Hiramatsu } 41199ca4233SMasami Hiramatsu 4125a6f6314SMasami Hiramatsu /* 4135a6f6314SMasami Hiramatsu * Convert trace point to probe point with debuginfo 4145a6f6314SMasami Hiramatsu */ 4155a6f6314SMasami Hiramatsu static int find_perf_probe_point_from_dwarf(struct probe_trace_point *tp, 4165a6f6314SMasami Hiramatsu struct perf_probe_point *pp, 4175a6f6314SMasami Hiramatsu bool is_kprobe) 4185a6f6314SMasami Hiramatsu { 4195a6f6314SMasami Hiramatsu struct debuginfo *dinfo = NULL; 4205a6f6314SMasami Hiramatsu unsigned long stext = 0; 4215a6f6314SMasami Hiramatsu u64 addr = tp->address; 4225a6f6314SMasami Hiramatsu int ret = -ENOENT; 4235a6f6314SMasami Hiramatsu 4245a6f6314SMasami Hiramatsu /* convert the address to dwarf address */ 4255a6f6314SMasami Hiramatsu if (!is_kprobe) { 4265a6f6314SMasami Hiramatsu if (!addr) { 4275a6f6314SMasami Hiramatsu ret = -EINVAL; 4285a6f6314SMasami Hiramatsu goto error; 4295a6f6314SMasami Hiramatsu } 4305a6f6314SMasami Hiramatsu ret = get_text_start_address(tp->module, &stext); 4315a6f6314SMasami Hiramatsu if (ret < 0) 4325a6f6314SMasami Hiramatsu goto error; 4335a6f6314SMasami Hiramatsu addr += stext; 4345a6f6314SMasami Hiramatsu } else { 4355a6f6314SMasami Hiramatsu addr = kernel_get_symbol_address_by_name(tp->symbol, false); 4365a6f6314SMasami Hiramatsu if (addr == 0) 4375a6f6314SMasami Hiramatsu goto error; 4385a6f6314SMasami Hiramatsu addr += tp->offset; 4395a6f6314SMasami Hiramatsu } 4405a6f6314SMasami Hiramatsu 4415a6f6314SMasami Hiramatsu pr_debug("try to find information at %" PRIx64 " in %s\n", addr, 4425a6f6314SMasami Hiramatsu tp->module ? : "kernel"); 4435a6f6314SMasami Hiramatsu 44492561cb7SMasami Hiramatsu dinfo = open_debuginfo(tp->module, verbose == 0); 4455a6f6314SMasami Hiramatsu if (dinfo) { 4465a6f6314SMasami Hiramatsu ret = debuginfo__find_probe_point(dinfo, 4475a6f6314SMasami Hiramatsu (unsigned long)addr, pp); 4485a6f6314SMasami Hiramatsu debuginfo__delete(dinfo); 44992561cb7SMasami Hiramatsu } else 4505a6f6314SMasami Hiramatsu ret = -ENOENT; 4515a6f6314SMasami Hiramatsu 4525a6f6314SMasami Hiramatsu if (ret > 0) { 4535a6f6314SMasami Hiramatsu pp->retprobe = tp->retprobe; 4545a6f6314SMasami Hiramatsu return 0; 4555a6f6314SMasami Hiramatsu } 4565a6f6314SMasami Hiramatsu error: 4575a6f6314SMasami Hiramatsu pr_debug("Failed to find corresponding probes from debuginfo.\n"); 4585a6f6314SMasami Hiramatsu return ret ? : -ENOENT; 4595a6f6314SMasami Hiramatsu } 4605a6f6314SMasami Hiramatsu 461fb7345bbSMasami Hiramatsu static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, 462fb7345bbSMasami Hiramatsu int ntevs, const char *exec) 463fb7345bbSMasami Hiramatsu { 464fb7345bbSMasami Hiramatsu int i, ret = 0; 465eb948e50SMasami Hiramatsu unsigned long stext = 0; 466fb7345bbSMasami Hiramatsu 467fb7345bbSMasami Hiramatsu if (!exec) 468fb7345bbSMasami Hiramatsu return 0; 469fb7345bbSMasami Hiramatsu 470fb7345bbSMasami Hiramatsu ret = get_text_start_address(exec, &stext); 471fb7345bbSMasami Hiramatsu if (ret < 0) 472fb7345bbSMasami Hiramatsu return ret; 473fb7345bbSMasami Hiramatsu 474fb7345bbSMasami Hiramatsu for (i = 0; i < ntevs && ret >= 0; i++) { 475981a2379SMasami Hiramatsu /* point.address is the addres of point.symbol + point.offset */ 476eb948e50SMasami Hiramatsu tevs[i].point.address -= stext; 477fb7345bbSMasami Hiramatsu tevs[i].point.module = strdup(exec); 478eb948e50SMasami Hiramatsu if (!tevs[i].point.module) { 479fb7345bbSMasami Hiramatsu ret = -ENOMEM; 480fb7345bbSMasami Hiramatsu break; 481fb7345bbSMasami Hiramatsu } 482fb7345bbSMasami Hiramatsu tevs[i].uprobes = true; 483fb7345bbSMasami Hiramatsu } 484fb7345bbSMasami Hiramatsu 485fb7345bbSMasami Hiramatsu return ret; 486fb7345bbSMasami Hiramatsu } 487fb7345bbSMasami Hiramatsu 488190b57fcSMasami Hiramatsu static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, 489190b57fcSMasami Hiramatsu int ntevs, const char *module) 490190b57fcSMasami Hiramatsu { 49114a8fd7cSMasami Hiramatsu int i, ret = 0; 49214a8fd7cSMasami Hiramatsu char *tmp; 49314a8fd7cSMasami Hiramatsu 49414a8fd7cSMasami Hiramatsu if (!module) 49514a8fd7cSMasami Hiramatsu return 0; 49614a8fd7cSMasami Hiramatsu 49714a8fd7cSMasami Hiramatsu tmp = strrchr(module, '/'); 49814a8fd7cSMasami Hiramatsu if (tmp) { 49914a8fd7cSMasami Hiramatsu /* This is a module path -- get the module name */ 50014a8fd7cSMasami Hiramatsu module = strdup(tmp + 1); 50114a8fd7cSMasami Hiramatsu if (!module) 50214a8fd7cSMasami Hiramatsu return -ENOMEM; 50314a8fd7cSMasami Hiramatsu tmp = strchr(module, '.'); 50414a8fd7cSMasami Hiramatsu if (tmp) 50514a8fd7cSMasami Hiramatsu *tmp = '\0'; 50614a8fd7cSMasami Hiramatsu tmp = (char *)module; /* For free() */ 50714a8fd7cSMasami Hiramatsu } 50814a8fd7cSMasami Hiramatsu 509190b57fcSMasami Hiramatsu for (i = 0; i < ntevs; i++) { 510190b57fcSMasami Hiramatsu tevs[i].point.module = strdup(module); 51114a8fd7cSMasami Hiramatsu if (!tevs[i].point.module) { 51214a8fd7cSMasami Hiramatsu ret = -ENOMEM; 51314a8fd7cSMasami Hiramatsu break; 514190b57fcSMasami Hiramatsu } 51514a8fd7cSMasami Hiramatsu } 51614a8fd7cSMasami Hiramatsu 51714a8fd7cSMasami Hiramatsu free(tmp); 51814a8fd7cSMasami Hiramatsu return ret; 519190b57fcSMasami Hiramatsu } 520190b57fcSMasami Hiramatsu 521dfef99cdSMasami Hiramatsu /* Post processing the probe events */ 522dfef99cdSMasami Hiramatsu static int post_process_probe_trace_events(struct probe_trace_event *tevs, 523dfef99cdSMasami Hiramatsu int ntevs, const char *module, 524dfef99cdSMasami Hiramatsu bool uprobe) 525dfef99cdSMasami Hiramatsu { 526dfef99cdSMasami Hiramatsu struct ref_reloc_sym *reloc_sym; 527dfef99cdSMasami Hiramatsu char *tmp; 528dfef99cdSMasami Hiramatsu int i; 529dfef99cdSMasami Hiramatsu 530dfef99cdSMasami Hiramatsu if (uprobe) 531dfef99cdSMasami Hiramatsu return add_exec_to_probe_trace_events(tevs, ntevs, module); 532dfef99cdSMasami Hiramatsu 533dfef99cdSMasami Hiramatsu /* Note that currently ref_reloc_sym based probe is not for drivers */ 534dfef99cdSMasami Hiramatsu if (module) 535dfef99cdSMasami Hiramatsu return add_module_to_probe_trace_events(tevs, ntevs, module); 536dfef99cdSMasami Hiramatsu 5378f33f7deSMasami Hiramatsu reloc_sym = kernel_get_ref_reloc_sym(); 538dfef99cdSMasami Hiramatsu if (!reloc_sym) { 539dfef99cdSMasami Hiramatsu pr_warning("Relocated base symbol is not found!\n"); 540dfef99cdSMasami Hiramatsu return -EINVAL; 541dfef99cdSMasami Hiramatsu } 542dfef99cdSMasami Hiramatsu 543dfef99cdSMasami Hiramatsu for (i = 0; i < ntevs; i++) { 54425dd9171SNamhyung Kim if (tevs[i].point.address && !tevs[i].point.retprobe) { 545dfef99cdSMasami Hiramatsu tmp = strdup(reloc_sym->name); 546dfef99cdSMasami Hiramatsu if (!tmp) 547dfef99cdSMasami Hiramatsu return -ENOMEM; 548dfef99cdSMasami Hiramatsu free(tevs[i].point.symbol); 549dfef99cdSMasami Hiramatsu tevs[i].point.symbol = tmp; 550dfef99cdSMasami Hiramatsu tevs[i].point.offset = tevs[i].point.address - 551dfef99cdSMasami Hiramatsu reloc_sym->unrelocated_addr; 552dfef99cdSMasami Hiramatsu } 553dfef99cdSMasami Hiramatsu } 554dfef99cdSMasami Hiramatsu return 0; 555dfef99cdSMasami Hiramatsu } 556dfef99cdSMasami Hiramatsu 5574b4da7f7SMasami Hiramatsu /* Try to find perf_probe_event with debuginfo */ 5580e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 5590e60836bSSrikar Dronamraju struct probe_trace_event **tevs, 5604eced234SSrikar Dronamraju int max_tevs, const char *target) 5614b4da7f7SMasami Hiramatsu { 5624b4da7f7SMasami Hiramatsu bool need_dwarf = perf_probe_event_need_dwarf(pev); 563*9b118acaSMasami Hiramatsu struct perf_probe_point tmp; 564225466f1SSrikar Dronamraju struct debuginfo *dinfo; 565190b57fcSMasami Hiramatsu int ntevs, ret = 0; 5664b4da7f7SMasami Hiramatsu 56792561cb7SMasami Hiramatsu dinfo = open_debuginfo(target, !need_dwarf); 568225466f1SSrikar Dronamraju 569ff741783SMasami Hiramatsu if (!dinfo) { 57092561cb7SMasami Hiramatsu if (need_dwarf) 571ff741783SMasami Hiramatsu return -ENOENT; 572ff741783SMasami Hiramatsu pr_debug("Could not open debuginfo. Try to use symbols.\n"); 5734b4da7f7SMasami Hiramatsu return 0; 5744b4da7f7SMasami Hiramatsu } 5754b4da7f7SMasami Hiramatsu 576dfef99cdSMasami Hiramatsu pr_debug("Try to find probe point from debuginfo.\n"); 577ff741783SMasami Hiramatsu /* Searching trace events corresponding to a probe event */ 578ff741783SMasami Hiramatsu ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs); 579ff741783SMasami Hiramatsu 580*9b118acaSMasami Hiramatsu if (ntevs == 0) { /* Not found, retry with an alternative */ 581*9b118acaSMasami Hiramatsu ret = get_alternative_probe_event(dinfo, pev, &tmp, target); 582*9b118acaSMasami Hiramatsu if (!ret) { 583*9b118acaSMasami Hiramatsu ntevs = debuginfo__find_trace_events(dinfo, pev, 584*9b118acaSMasami Hiramatsu tevs, max_tevs); 585*9b118acaSMasami Hiramatsu /* 586*9b118acaSMasami Hiramatsu * Write back to the original probe_event for 587*9b118acaSMasami Hiramatsu * setting appropriate (user given) event name 588*9b118acaSMasami Hiramatsu */ 589*9b118acaSMasami Hiramatsu clear_perf_probe_point(&pev->point); 590*9b118acaSMasami Hiramatsu memcpy(&pev->point, &tmp, sizeof(tmp)); 591*9b118acaSMasami Hiramatsu } 592*9b118acaSMasami Hiramatsu } 593*9b118acaSMasami Hiramatsu 594ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 5954b4da7f7SMasami Hiramatsu 596146a1439SMasami Hiramatsu if (ntevs > 0) { /* Succeeded to find trace events */ 597dfef99cdSMasami Hiramatsu pr_debug("Found %d probe_trace_events.\n", ntevs); 598dfef99cdSMasami Hiramatsu ret = post_process_probe_trace_events(*tevs, ntevs, 599dfef99cdSMasami Hiramatsu target, pev->uprobes); 600981d05adSMasami Hiramatsu if (ret < 0) { 601981d05adSMasami Hiramatsu clear_probe_trace_events(*tevs, ntevs); 602981d05adSMasami Hiramatsu zfree(tevs); 603981d05adSMasami Hiramatsu } 604190b57fcSMasami Hiramatsu return ret < 0 ? ret : ntevs; 605146a1439SMasami Hiramatsu } 6064b4da7f7SMasami Hiramatsu 607146a1439SMasami Hiramatsu if (ntevs == 0) { /* No error but failed to find probe point. */ 608906451b9SMasami Hiramatsu pr_warning("Probe point '%s' not found in debuginfo.\n", 6094b4da7f7SMasami Hiramatsu synthesize_perf_probe_point(&pev->point)); 610906451b9SMasami Hiramatsu if (need_dwarf) 611146a1439SMasami Hiramatsu return -ENOENT; 612906451b9SMasami Hiramatsu return 0; 613146a1439SMasami Hiramatsu } 614146a1439SMasami Hiramatsu /* Error path : ntevs < 0 */ 61515eca306SMasami Hiramatsu pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); 61615eca306SMasami Hiramatsu if (ntevs == -EBADF) { 61715eca306SMasami Hiramatsu pr_warning("Warning: No dwarf info found in the vmlinux - " 61815eca306SMasami Hiramatsu "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); 61915eca306SMasami Hiramatsu if (!need_dwarf) { 6200e43e5d2SMasami Hiramatsu pr_debug("Trying to use symbols.\n"); 6214b4da7f7SMasami Hiramatsu return 0; 6224b4da7f7SMasami Hiramatsu } 62315eca306SMasami Hiramatsu } 62415eca306SMasami Hiramatsu return ntevs; 62515eca306SMasami Hiramatsu } 6264b4da7f7SMasami Hiramatsu 6277cf0b79eSMasami Hiramatsu /* 6287cf0b79eSMasami Hiramatsu * Find a src file from a DWARF tag path. Prepend optional source path prefix 6297cf0b79eSMasami Hiramatsu * and chop off leading directories that do not exist. Result is passed back as 6307cf0b79eSMasami Hiramatsu * a newly allocated path on success. 6317cf0b79eSMasami Hiramatsu * Return 0 if file was found and readable, -errno otherwise. 6327cf0b79eSMasami Hiramatsu */ 6336a330a3cSMasami Hiramatsu static int get_real_path(const char *raw_path, const char *comp_dir, 6346a330a3cSMasami Hiramatsu char **new_path) 6357cf0b79eSMasami Hiramatsu { 6366a330a3cSMasami Hiramatsu const char *prefix = symbol_conf.source_prefix; 6376a330a3cSMasami Hiramatsu 6386a330a3cSMasami Hiramatsu if (!prefix) { 6396a330a3cSMasami Hiramatsu if (raw_path[0] != '/' && comp_dir) 6406a330a3cSMasami Hiramatsu /* If not an absolute path, try to use comp_dir */ 6416a330a3cSMasami Hiramatsu prefix = comp_dir; 6426a330a3cSMasami Hiramatsu else { 6437cf0b79eSMasami Hiramatsu if (access(raw_path, R_OK) == 0) { 6447cf0b79eSMasami Hiramatsu *new_path = strdup(raw_path); 64538ae502bSArnaldo Carvalho de Melo return *new_path ? 0 : -ENOMEM; 6467cf0b79eSMasami Hiramatsu } else 6477cf0b79eSMasami Hiramatsu return -errno; 6487cf0b79eSMasami Hiramatsu } 6496a330a3cSMasami Hiramatsu } 6507cf0b79eSMasami Hiramatsu 6516a330a3cSMasami Hiramatsu *new_path = malloc((strlen(prefix) + strlen(raw_path) + 2)); 6527cf0b79eSMasami Hiramatsu if (!*new_path) 6537cf0b79eSMasami Hiramatsu return -ENOMEM; 6547cf0b79eSMasami Hiramatsu 6557cf0b79eSMasami Hiramatsu for (;;) { 6566a330a3cSMasami Hiramatsu sprintf(*new_path, "%s/%s", prefix, raw_path); 6577cf0b79eSMasami Hiramatsu 6587cf0b79eSMasami Hiramatsu if (access(*new_path, R_OK) == 0) 6597cf0b79eSMasami Hiramatsu return 0; 6607cf0b79eSMasami Hiramatsu 661eb47cb2eSMasami Hiramatsu if (!symbol_conf.source_prefix) { 6626a330a3cSMasami Hiramatsu /* In case of searching comp_dir, don't retry */ 663eb47cb2eSMasami Hiramatsu zfree(new_path); 6646a330a3cSMasami Hiramatsu return -errno; 665eb47cb2eSMasami Hiramatsu } 6666a330a3cSMasami Hiramatsu 6677cf0b79eSMasami Hiramatsu switch (errno) { 6687cf0b79eSMasami Hiramatsu case ENAMETOOLONG: 6697cf0b79eSMasami Hiramatsu case ENOENT: 6707cf0b79eSMasami Hiramatsu case EROFS: 6717cf0b79eSMasami Hiramatsu case EFAULT: 6727cf0b79eSMasami Hiramatsu raw_path = strchr(++raw_path, '/'); 6737cf0b79eSMasami Hiramatsu if (!raw_path) { 67404662523SArnaldo Carvalho de Melo zfree(new_path); 6757cf0b79eSMasami Hiramatsu return -ENOENT; 6767cf0b79eSMasami Hiramatsu } 6777cf0b79eSMasami Hiramatsu continue; 6787cf0b79eSMasami Hiramatsu 6797cf0b79eSMasami Hiramatsu default: 68004662523SArnaldo Carvalho de Melo zfree(new_path); 6817cf0b79eSMasami Hiramatsu return -errno; 6827cf0b79eSMasami Hiramatsu } 6837cf0b79eSMasami Hiramatsu } 6847cf0b79eSMasami Hiramatsu } 6857cf0b79eSMasami Hiramatsu 6864b4da7f7SMasami Hiramatsu #define LINEBUF_SIZE 256 6874b4da7f7SMasami Hiramatsu #define NR_ADDITIONAL_LINES 2 6884b4da7f7SMasami Hiramatsu 689fde52dbdSFranck Bui-Huu static int __show_one_line(FILE *fp, int l, bool skip, bool show_num) 6904b4da7f7SMasami Hiramatsu { 6915f03cba4SMasami Hiramatsu char buf[LINEBUF_SIZE], sbuf[STRERR_BUFSIZE]; 692befe3414SFranck Bui-Huu const char *color = show_num ? "" : PERF_COLOR_BLUE; 693befe3414SFranck Bui-Huu const char *prefix = NULL; 6944b4da7f7SMasami Hiramatsu 695befe3414SFranck Bui-Huu do { 6964b4da7f7SMasami Hiramatsu if (fgets(buf, LINEBUF_SIZE, fp) == NULL) 6974b4da7f7SMasami Hiramatsu goto error; 698befe3414SFranck Bui-Huu if (skip) 699befe3414SFranck Bui-Huu continue; 700befe3414SFranck Bui-Huu if (!prefix) { 701befe3414SFranck Bui-Huu prefix = show_num ? "%7d " : " "; 702befe3414SFranck Bui-Huu color_fprintf(stdout, color, prefix, l); 7034b4da7f7SMasami Hiramatsu } 704befe3414SFranck Bui-Huu color_fprintf(stdout, color, "%s", buf); 7054b4da7f7SMasami Hiramatsu 706befe3414SFranck Bui-Huu } while (strchr(buf, '\n') == NULL); 707146a1439SMasami Hiramatsu 708fde52dbdSFranck Bui-Huu return 1; 7094b4da7f7SMasami Hiramatsu error: 710fde52dbdSFranck Bui-Huu if (ferror(fp)) { 7115f03cba4SMasami Hiramatsu pr_warning("File read error: %s\n", 7125f03cba4SMasami Hiramatsu strerror_r(errno, sbuf, sizeof(sbuf))); 713146a1439SMasami Hiramatsu return -1; 7144b4da7f7SMasami Hiramatsu } 715fde52dbdSFranck Bui-Huu return 0; 716fde52dbdSFranck Bui-Huu } 717fde52dbdSFranck Bui-Huu 718fde52dbdSFranck Bui-Huu static int _show_one_line(FILE *fp, int l, bool skip, bool show_num) 719fde52dbdSFranck Bui-Huu { 720fde52dbdSFranck Bui-Huu int rv = __show_one_line(fp, l, skip, show_num); 721fde52dbdSFranck Bui-Huu if (rv == 0) { 722fde52dbdSFranck Bui-Huu pr_warning("Source file is shorter than expected.\n"); 723fde52dbdSFranck Bui-Huu rv = -1; 724fde52dbdSFranck Bui-Huu } 725fde52dbdSFranck Bui-Huu return rv; 726fde52dbdSFranck Bui-Huu } 727fde52dbdSFranck Bui-Huu 728fde52dbdSFranck Bui-Huu #define show_one_line_with_num(f,l) _show_one_line(f,l,false,true) 729fde52dbdSFranck Bui-Huu #define show_one_line(f,l) _show_one_line(f,l,false,false) 730fde52dbdSFranck Bui-Huu #define skip_one_line(f,l) _show_one_line(f,l,true,false) 731fde52dbdSFranck Bui-Huu #define show_one_line_or_eof(f,l) __show_one_line(f,l,false,false) 7324b4da7f7SMasami Hiramatsu 7334b4da7f7SMasami Hiramatsu /* 7344b4da7f7SMasami Hiramatsu * Show line-range always requires debuginfo to find source file and 7354b4da7f7SMasami Hiramatsu * line number. 7364b4da7f7SMasami Hiramatsu */ 737ee45b6c2SMasami Hiramatsu static int __show_line_range(struct line_range *lr, const char *module) 7384b4da7f7SMasami Hiramatsu { 739d3b63d7aSMasami Hiramatsu int l = 1; 7405a62257aSMasami Hiramatsu struct int_node *ln; 741ff741783SMasami Hiramatsu struct debuginfo *dinfo; 7424b4da7f7SMasami Hiramatsu FILE *fp; 743ff741783SMasami Hiramatsu int ret; 7447cf0b79eSMasami Hiramatsu char *tmp; 7455f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 7464b4da7f7SMasami Hiramatsu 7474b4da7f7SMasami Hiramatsu /* Search a line range */ 74892561cb7SMasami Hiramatsu dinfo = open_debuginfo(module, false); 74992561cb7SMasami Hiramatsu if (!dinfo) 750ff741783SMasami Hiramatsu return -ENOENT; 751146a1439SMasami Hiramatsu 752ff741783SMasami Hiramatsu ret = debuginfo__find_line_range(dinfo, lr); 753ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 7545ee05b88SMasami Hiramatsu if (ret == 0 || ret == -ENOENT) { 755146a1439SMasami Hiramatsu pr_warning("Specified source line is not found.\n"); 756146a1439SMasami Hiramatsu return -ENOENT; 757146a1439SMasami Hiramatsu } else if (ret < 0) { 7585ee05b88SMasami Hiramatsu pr_warning("Debuginfo analysis failed.\n"); 759146a1439SMasami Hiramatsu return ret; 760146a1439SMasami Hiramatsu } 7614b4da7f7SMasami Hiramatsu 7627cf0b79eSMasami Hiramatsu /* Convert source file path */ 7637cf0b79eSMasami Hiramatsu tmp = lr->path; 7646a330a3cSMasami Hiramatsu ret = get_real_path(tmp, lr->comp_dir, &lr->path); 7657cf0b79eSMasami Hiramatsu free(tmp); /* Free old path */ 7667cf0b79eSMasami Hiramatsu if (ret < 0) { 7675ee05b88SMasami Hiramatsu pr_warning("Failed to find source file path.\n"); 7687cf0b79eSMasami Hiramatsu return ret; 7697cf0b79eSMasami Hiramatsu } 7707cf0b79eSMasami Hiramatsu 7714b4da7f7SMasami Hiramatsu setup_pager(); 7724b4da7f7SMasami Hiramatsu 7734b4da7f7SMasami Hiramatsu if (lr->function) 7748737ebdeSMasami Hiramatsu fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path, 7754b4da7f7SMasami Hiramatsu lr->start - lr->offset); 7764b4da7f7SMasami Hiramatsu else 77762c15fc4SFranck Bui-Huu fprintf(stdout, "<%s:%d>\n", lr->path, lr->start); 7784b4da7f7SMasami Hiramatsu 7794b4da7f7SMasami Hiramatsu fp = fopen(lr->path, "r"); 780146a1439SMasami Hiramatsu if (fp == NULL) { 781146a1439SMasami Hiramatsu pr_warning("Failed to open %s: %s\n", lr->path, 7825f03cba4SMasami Hiramatsu strerror_r(errno, sbuf, sizeof(sbuf))); 783146a1439SMasami Hiramatsu return -errno; 784146a1439SMasami Hiramatsu } 7854b4da7f7SMasami Hiramatsu /* Skip to starting line number */ 78644b81e92SFranck Bui-Huu while (l < lr->start) { 787fde52dbdSFranck Bui-Huu ret = skip_one_line(fp, l++); 788146a1439SMasami Hiramatsu if (ret < 0) 789146a1439SMasami Hiramatsu goto end; 79044b81e92SFranck Bui-Huu } 7914b4da7f7SMasami Hiramatsu 7925a62257aSMasami Hiramatsu intlist__for_each(ln, lr->line_list) { 7935a62257aSMasami Hiramatsu for (; ln->i > l; l++) { 794fde52dbdSFranck Bui-Huu ret = show_one_line(fp, l - lr->offset); 79544b81e92SFranck Bui-Huu if (ret < 0) 79644b81e92SFranck Bui-Huu goto end; 79744b81e92SFranck Bui-Huu } 798fde52dbdSFranck Bui-Huu ret = show_one_line_with_num(fp, l++ - lr->offset); 799146a1439SMasami Hiramatsu if (ret < 0) 800146a1439SMasami Hiramatsu goto end; 8014b4da7f7SMasami Hiramatsu } 8024b4da7f7SMasami Hiramatsu 8034b4da7f7SMasami Hiramatsu if (lr->end == INT_MAX) 8044b4da7f7SMasami Hiramatsu lr->end = l + NR_ADDITIONAL_LINES; 805fde52dbdSFranck Bui-Huu while (l <= lr->end) { 806fde52dbdSFranck Bui-Huu ret = show_one_line_or_eof(fp, l++ - lr->offset); 807fde52dbdSFranck Bui-Huu if (ret <= 0) 80844b81e92SFranck Bui-Huu break; 80944b81e92SFranck Bui-Huu } 810146a1439SMasami Hiramatsu end: 8114b4da7f7SMasami Hiramatsu fclose(fp); 812146a1439SMasami Hiramatsu return ret; 8134b4da7f7SMasami Hiramatsu } 8144b4da7f7SMasami Hiramatsu 8152b394bc4SMasami Hiramatsu int show_line_range(struct line_range *lr, const char *module, bool user) 816ee45b6c2SMasami Hiramatsu { 817ee45b6c2SMasami Hiramatsu int ret; 818ee45b6c2SMasami Hiramatsu 8192b394bc4SMasami Hiramatsu ret = init_symbol_maps(user); 820ee45b6c2SMasami Hiramatsu if (ret < 0) 821ee45b6c2SMasami Hiramatsu return ret; 822ee45b6c2SMasami Hiramatsu ret = __show_line_range(lr, module); 823ee45b6c2SMasami Hiramatsu exit_symbol_maps(); 824ee45b6c2SMasami Hiramatsu 825ee45b6c2SMasami Hiramatsu return ret; 826ee45b6c2SMasami Hiramatsu } 827ee45b6c2SMasami Hiramatsu 828ff741783SMasami Hiramatsu static int show_available_vars_at(struct debuginfo *dinfo, 829ff741783SMasami Hiramatsu struct perf_probe_event *pev, 830bd09d7b5SMasami Hiramatsu int max_vls, struct strfilter *_filter, 831*9b118acaSMasami Hiramatsu bool externs, const char *target) 832cf6eb489SMasami Hiramatsu { 833cf6eb489SMasami Hiramatsu char *buf; 834bd09d7b5SMasami Hiramatsu int ret, i, nvars; 835cf6eb489SMasami Hiramatsu struct str_node *node; 836cf6eb489SMasami Hiramatsu struct variable_list *vls = NULL, *vl; 837*9b118acaSMasami Hiramatsu struct perf_probe_point tmp; 838bd09d7b5SMasami Hiramatsu const char *var; 839cf6eb489SMasami Hiramatsu 840cf6eb489SMasami Hiramatsu buf = synthesize_perf_probe_point(&pev->point); 841cf6eb489SMasami Hiramatsu if (!buf) 842cf6eb489SMasami Hiramatsu return -EINVAL; 843cf6eb489SMasami Hiramatsu pr_debug("Searching variables at %s\n", buf); 844cf6eb489SMasami Hiramatsu 845ff741783SMasami Hiramatsu ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, 846ff741783SMasami Hiramatsu max_vls, externs); 847*9b118acaSMasami Hiramatsu if (!ret) { /* Not found, retry with an alternative */ 848*9b118acaSMasami Hiramatsu ret = get_alternative_probe_event(dinfo, pev, &tmp, target); 849*9b118acaSMasami Hiramatsu if (!ret) { 850*9b118acaSMasami Hiramatsu ret = debuginfo__find_available_vars_at(dinfo, pev, 851*9b118acaSMasami Hiramatsu &vls, max_vls, externs); 852*9b118acaSMasami Hiramatsu /* Release the old probe_point */ 853*9b118acaSMasami Hiramatsu clear_perf_probe_point(&tmp); 854*9b118acaSMasami Hiramatsu } 855*9b118acaSMasami Hiramatsu } 856bd09d7b5SMasami Hiramatsu if (ret <= 0) { 85769e96eaaSMasami Hiramatsu if (ret == 0 || ret == -ENOENT) { 85869e96eaaSMasami Hiramatsu pr_err("Failed to find the address of %s\n", buf); 85969e96eaaSMasami Hiramatsu ret = -ENOENT; 86069e96eaaSMasami Hiramatsu } else 86169e96eaaSMasami Hiramatsu pr_warning("Debuginfo analysis failed.\n"); 862bd09d7b5SMasami Hiramatsu goto end; 863bd09d7b5SMasami Hiramatsu } 86469e96eaaSMasami Hiramatsu 865bd09d7b5SMasami Hiramatsu /* Some variables are found */ 866cf6eb489SMasami Hiramatsu fprintf(stdout, "Available variables at %s\n", buf); 867cf6eb489SMasami Hiramatsu for (i = 0; i < ret; i++) { 868cf6eb489SMasami Hiramatsu vl = &vls[i]; 869cf6eb489SMasami Hiramatsu /* 870cf6eb489SMasami Hiramatsu * A probe point might be converted to 871cf6eb489SMasami Hiramatsu * several trace points. 872cf6eb489SMasami Hiramatsu */ 873cf6eb489SMasami Hiramatsu fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, 874cf6eb489SMasami Hiramatsu vl->point.offset); 87574cf249dSArnaldo Carvalho de Melo zfree(&vl->point.symbol); 876bd09d7b5SMasami Hiramatsu nvars = 0; 877cf6eb489SMasami Hiramatsu if (vl->vars) { 878bd09d7b5SMasami Hiramatsu strlist__for_each(node, vl->vars) { 879bd09d7b5SMasami Hiramatsu var = strchr(node->s, '\t') + 1; 880bd09d7b5SMasami Hiramatsu if (strfilter__compare(_filter, var)) { 881cf6eb489SMasami Hiramatsu fprintf(stdout, "\t\t%s\n", node->s); 882bd09d7b5SMasami Hiramatsu nvars++; 883bd09d7b5SMasami Hiramatsu } 884bd09d7b5SMasami Hiramatsu } 885cf6eb489SMasami Hiramatsu strlist__delete(vl->vars); 886bd09d7b5SMasami Hiramatsu } 887bd09d7b5SMasami Hiramatsu if (nvars == 0) 888bd09d7b5SMasami Hiramatsu fprintf(stdout, "\t\t(No matched variables)\n"); 889cf6eb489SMasami Hiramatsu } 890cf6eb489SMasami Hiramatsu free(vls); 891bd09d7b5SMasami Hiramatsu end: 892cf6eb489SMasami Hiramatsu free(buf); 893cf6eb489SMasami Hiramatsu return ret; 894cf6eb489SMasami Hiramatsu } 895cf6eb489SMasami Hiramatsu 896cf6eb489SMasami Hiramatsu /* Show available variables on given probe point */ 897cf6eb489SMasami Hiramatsu int show_available_vars(struct perf_probe_event *pevs, int npevs, 898bd09d7b5SMasami Hiramatsu int max_vls, const char *module, 899bd09d7b5SMasami Hiramatsu struct strfilter *_filter, bool externs) 900cf6eb489SMasami Hiramatsu { 901ff741783SMasami Hiramatsu int i, ret = 0; 902ff741783SMasami Hiramatsu struct debuginfo *dinfo; 903cf6eb489SMasami Hiramatsu 9042b394bc4SMasami Hiramatsu ret = init_symbol_maps(pevs->uprobes); 905cf6eb489SMasami Hiramatsu if (ret < 0) 906cf6eb489SMasami Hiramatsu return ret; 907cf6eb489SMasami Hiramatsu 90892561cb7SMasami Hiramatsu dinfo = open_debuginfo(module, false); 909ff741783SMasami Hiramatsu if (!dinfo) { 910ee45b6c2SMasami Hiramatsu ret = -ENOENT; 911ee45b6c2SMasami Hiramatsu goto out; 912ff741783SMasami Hiramatsu } 913ff741783SMasami Hiramatsu 914cc446446SMasami Hiramatsu setup_pager(); 915cc446446SMasami Hiramatsu 916ff741783SMasami Hiramatsu for (i = 0; i < npevs && ret >= 0; i++) 917ff741783SMasami Hiramatsu ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter, 918*9b118acaSMasami Hiramatsu externs, module); 919ff741783SMasami Hiramatsu 920ff741783SMasami Hiramatsu debuginfo__delete(dinfo); 921ee45b6c2SMasami Hiramatsu out: 922ee45b6c2SMasami Hiramatsu exit_symbol_maps(); 923cf6eb489SMasami Hiramatsu return ret; 924cf6eb489SMasami Hiramatsu } 925cf6eb489SMasami Hiramatsu 92689fe808aSIngo Molnar #else /* !HAVE_DWARF_SUPPORT */ 9274b4da7f7SMasami Hiramatsu 9285a6f6314SMasami Hiramatsu static int 9295a6f6314SMasami Hiramatsu find_perf_probe_point_from_dwarf(struct probe_trace_point *tp __maybe_unused, 9305a6f6314SMasami Hiramatsu struct perf_probe_point *pp __maybe_unused, 9315a6f6314SMasami Hiramatsu bool is_kprobe __maybe_unused) 9324b4da7f7SMasami Hiramatsu { 9335a6f6314SMasami Hiramatsu return -ENOSYS; 9344b4da7f7SMasami Hiramatsu } 9354b4da7f7SMasami Hiramatsu 9360e60836bSSrikar Dronamraju static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 9371d037ca1SIrina Tirdea struct probe_trace_event **tevs __maybe_unused, 9381d027ee9SArnaldo Carvalho de Melo int max_tevs __maybe_unused, 9391d027ee9SArnaldo Carvalho de Melo const char *target __maybe_unused) 9404b4da7f7SMasami Hiramatsu { 941146a1439SMasami Hiramatsu if (perf_probe_event_need_dwarf(pev)) { 942146a1439SMasami Hiramatsu pr_warning("Debuginfo-analysis is not supported.\n"); 943146a1439SMasami Hiramatsu return -ENOSYS; 944146a1439SMasami Hiramatsu } 945225466f1SSrikar Dronamraju 9464b4da7f7SMasami Hiramatsu return 0; 9474b4da7f7SMasami Hiramatsu } 9484b4da7f7SMasami Hiramatsu 9491d037ca1SIrina Tirdea int show_line_range(struct line_range *lr __maybe_unused, 9502b394bc4SMasami Hiramatsu const char *module __maybe_unused, 9512b394bc4SMasami Hiramatsu bool user __maybe_unused) 9524b4da7f7SMasami Hiramatsu { 953146a1439SMasami Hiramatsu pr_warning("Debuginfo-analysis is not supported.\n"); 954146a1439SMasami Hiramatsu return -ENOSYS; 9554b4da7f7SMasami Hiramatsu } 9564b4da7f7SMasami Hiramatsu 9571d037ca1SIrina Tirdea int show_available_vars(struct perf_probe_event *pevs __maybe_unused, 9581d037ca1SIrina Tirdea int npevs __maybe_unused, int max_vls __maybe_unused, 9591d037ca1SIrina Tirdea const char *module __maybe_unused, 9601d037ca1SIrina Tirdea struct strfilter *filter __maybe_unused, 9611d037ca1SIrina Tirdea bool externs __maybe_unused) 962cf6eb489SMasami Hiramatsu { 963cf6eb489SMasami Hiramatsu pr_warning("Debuginfo-analysis is not supported.\n"); 964cf6eb489SMasami Hiramatsu return -ENOSYS; 965cf6eb489SMasami Hiramatsu } 966e0faa8d3SMasami Hiramatsu #endif 967e0faa8d3SMasami Hiramatsu 968e53b00d3SMasami Hiramatsu void line_range__clear(struct line_range *lr) 969e53b00d3SMasami Hiramatsu { 970e53b00d3SMasami Hiramatsu free(lr->function); 971e53b00d3SMasami Hiramatsu free(lr->file); 972e53b00d3SMasami Hiramatsu free(lr->path); 973e53b00d3SMasami Hiramatsu free(lr->comp_dir); 9745a62257aSMasami Hiramatsu intlist__delete(lr->line_list); 975e53b00d3SMasami Hiramatsu memset(lr, 0, sizeof(*lr)); 976e53b00d3SMasami Hiramatsu } 977e53b00d3SMasami Hiramatsu 9785a62257aSMasami Hiramatsu int line_range__init(struct line_range *lr) 979e53b00d3SMasami Hiramatsu { 980e53b00d3SMasami Hiramatsu memset(lr, 0, sizeof(*lr)); 9815a62257aSMasami Hiramatsu lr->line_list = intlist__new(NULL); 9825a62257aSMasami Hiramatsu if (!lr->line_list) 9835a62257aSMasami Hiramatsu return -ENOMEM; 9845a62257aSMasami Hiramatsu else 9855a62257aSMasami Hiramatsu return 0; 986e53b00d3SMasami Hiramatsu } 987e53b00d3SMasami Hiramatsu 98821dd9ae5SFranck Bui-Huu static int parse_line_num(char **ptr, int *val, const char *what) 98921dd9ae5SFranck Bui-Huu { 99021dd9ae5SFranck Bui-Huu const char *start = *ptr; 99121dd9ae5SFranck Bui-Huu 99221dd9ae5SFranck Bui-Huu errno = 0; 99321dd9ae5SFranck Bui-Huu *val = strtol(*ptr, ptr, 0); 99421dd9ae5SFranck Bui-Huu if (errno || *ptr == start) { 99521dd9ae5SFranck Bui-Huu semantic_error("'%s' is not a valid number.\n", what); 99621dd9ae5SFranck Bui-Huu return -EINVAL; 99721dd9ae5SFranck Bui-Huu } 99821dd9ae5SFranck Bui-Huu return 0; 99921dd9ae5SFranck Bui-Huu } 100021dd9ae5SFranck Bui-Huu 10019d95b580SFranck Bui-Huu /* 10029d95b580SFranck Bui-Huu * Stuff 'lr' according to the line range described by 'arg'. 10039d95b580SFranck Bui-Huu * The line range syntax is described by: 10049d95b580SFranck Bui-Huu * 10059d95b580SFranck Bui-Huu * SRC[:SLN[+NUM|-ELN]] 1006e116dfa1SMasami Hiramatsu * FNC[@SRC][:SLN[+NUM|-ELN]] 10079d95b580SFranck Bui-Huu */ 1008146a1439SMasami Hiramatsu int parse_line_range_desc(const char *arg, struct line_range *lr) 1009631c9defSMasami Hiramatsu { 1010e116dfa1SMasami Hiramatsu char *range, *file, *name = strdup(arg); 101121dd9ae5SFranck Bui-Huu int err; 10129d95b580SFranck Bui-Huu 101321dd9ae5SFranck Bui-Huu if (!name) 101421dd9ae5SFranck Bui-Huu return -ENOMEM; 101521dd9ae5SFranck Bui-Huu 101621dd9ae5SFranck Bui-Huu lr->start = 0; 101721dd9ae5SFranck Bui-Huu lr->end = INT_MAX; 101821dd9ae5SFranck Bui-Huu 101921dd9ae5SFranck Bui-Huu range = strchr(name, ':'); 102021dd9ae5SFranck Bui-Huu if (range) { 102121dd9ae5SFranck Bui-Huu *range++ = '\0'; 102221dd9ae5SFranck Bui-Huu 102321dd9ae5SFranck Bui-Huu err = parse_line_num(&range, &lr->start, "start line"); 102421dd9ae5SFranck Bui-Huu if (err) 102521dd9ae5SFranck Bui-Huu goto err; 102621dd9ae5SFranck Bui-Huu 102721dd9ae5SFranck Bui-Huu if (*range == '+' || *range == '-') { 102821dd9ae5SFranck Bui-Huu const char c = *range++; 102921dd9ae5SFranck Bui-Huu 103021dd9ae5SFranck Bui-Huu err = parse_line_num(&range, &lr->end, "end line"); 103121dd9ae5SFranck Bui-Huu if (err) 103221dd9ae5SFranck Bui-Huu goto err; 103321dd9ae5SFranck Bui-Huu 103421dd9ae5SFranck Bui-Huu if (c == '+') { 103521dd9ae5SFranck Bui-Huu lr->end += lr->start; 103621dd9ae5SFranck Bui-Huu /* 1037dda4ab34SMasami Hiramatsu * Adjust the number of lines here. 1038dda4ab34SMasami Hiramatsu * If the number of lines == 1, the 1039dda4ab34SMasami Hiramatsu * the end of line should be equal to 1040dda4ab34SMasami Hiramatsu * the start of line. 1041dda4ab34SMasami Hiramatsu */ 104221dd9ae5SFranck Bui-Huu lr->end--; 104321dd9ae5SFranck Bui-Huu } 104421dd9ae5SFranck Bui-Huu } 104521dd9ae5SFranck Bui-Huu 1046d3b63d7aSMasami Hiramatsu pr_debug("Line range is %d to %d\n", lr->start, lr->end); 104721dd9ae5SFranck Bui-Huu 104821dd9ae5SFranck Bui-Huu err = -EINVAL; 1049d3b63d7aSMasami Hiramatsu if (lr->start > lr->end) { 1050631c9defSMasami Hiramatsu semantic_error("Start line must be smaller" 1051146a1439SMasami Hiramatsu " than end line.\n"); 105221dd9ae5SFranck Bui-Huu goto err; 1053146a1439SMasami Hiramatsu } 105421dd9ae5SFranck Bui-Huu if (*range != '\0') { 105521dd9ae5SFranck Bui-Huu semantic_error("Tailing with invalid str '%s'.\n", range); 105621dd9ae5SFranck Bui-Huu goto err; 1057146a1439SMasami Hiramatsu } 1058d3b63d7aSMasami Hiramatsu } 105902b95dadSMasami Hiramatsu 1060e116dfa1SMasami Hiramatsu file = strchr(name, '@'); 1061e116dfa1SMasami Hiramatsu if (file) { 1062e116dfa1SMasami Hiramatsu *file = '\0'; 1063e116dfa1SMasami Hiramatsu lr->file = strdup(++file); 1064e116dfa1SMasami Hiramatsu if (lr->file == NULL) { 1065e116dfa1SMasami Hiramatsu err = -ENOMEM; 1066e116dfa1SMasami Hiramatsu goto err; 1067e116dfa1SMasami Hiramatsu } 1068e116dfa1SMasami Hiramatsu lr->function = name; 1069e116dfa1SMasami Hiramatsu } else if (strchr(name, '.')) 107021dd9ae5SFranck Bui-Huu lr->file = name; 1071631c9defSMasami Hiramatsu else 107221dd9ae5SFranck Bui-Huu lr->function = name; 1073146a1439SMasami Hiramatsu 1074146a1439SMasami Hiramatsu return 0; 107521dd9ae5SFranck Bui-Huu err: 107621dd9ae5SFranck Bui-Huu free(name); 107721dd9ae5SFranck Bui-Huu return err; 1078631c9defSMasami Hiramatsu } 1079631c9defSMasami Hiramatsu 1080b7702a21SMasami Hiramatsu /* Check the name is good for event/group */ 1081b7702a21SMasami Hiramatsu static bool check_event_name(const char *name) 1082b7702a21SMasami Hiramatsu { 1083b7702a21SMasami Hiramatsu if (!isalpha(*name) && *name != '_') 1084b7702a21SMasami Hiramatsu return false; 1085b7702a21SMasami Hiramatsu while (*++name != '\0') { 1086b7702a21SMasami Hiramatsu if (!isalpha(*name) && !isdigit(*name) && *name != '_') 1087b7702a21SMasami Hiramatsu return false; 1088b7702a21SMasami Hiramatsu } 1089b7702a21SMasami Hiramatsu return true; 1090b7702a21SMasami Hiramatsu } 1091b7702a21SMasami Hiramatsu 109250656eecSMasami Hiramatsu /* Parse probepoint definition. */ 1093146a1439SMasami Hiramatsu static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) 109450656eecSMasami Hiramatsu { 10954235b045SMasami Hiramatsu struct perf_probe_point *pp = &pev->point; 109650656eecSMasami Hiramatsu char *ptr, *tmp; 109750656eecSMasami Hiramatsu char c, nc = 0; 109850656eecSMasami Hiramatsu /* 109950656eecSMasami Hiramatsu * <Syntax> 11002a9c8c36SMasami Hiramatsu * perf probe [EVENT=]SRC[:LN|;PTN] 11012a9c8c36SMasami Hiramatsu * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] 1102af663d75SMasami Hiramatsu * 1103af663d75SMasami Hiramatsu * TODO:Group name support 110450656eecSMasami Hiramatsu */ 110550656eecSMasami Hiramatsu 11062a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";=@+%"); 11072a9c8c36SMasami Hiramatsu if (ptr && *ptr == '=') { /* Event name */ 1108af663d75SMasami Hiramatsu *ptr = '\0'; 1109af663d75SMasami Hiramatsu tmp = ptr + 1; 1110146a1439SMasami Hiramatsu if (strchr(arg, ':')) { 1111146a1439SMasami Hiramatsu semantic_error("Group name is not supported yet.\n"); 1112146a1439SMasami Hiramatsu return -ENOTSUP; 1113146a1439SMasami Hiramatsu } 1114146a1439SMasami Hiramatsu if (!check_event_name(arg)) { 1115b7702a21SMasami Hiramatsu semantic_error("%s is bad for event name -it must " 1116146a1439SMasami Hiramatsu "follow C symbol-naming rule.\n", arg); 1117146a1439SMasami Hiramatsu return -EINVAL; 1118146a1439SMasami Hiramatsu } 111902b95dadSMasami Hiramatsu pev->event = strdup(arg); 112002b95dadSMasami Hiramatsu if (pev->event == NULL) 112102b95dadSMasami Hiramatsu return -ENOMEM; 11224235b045SMasami Hiramatsu pev->group = NULL; 1123af663d75SMasami Hiramatsu arg = tmp; 1124af663d75SMasami Hiramatsu } 1125af663d75SMasami Hiramatsu 11262a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";:+@%"); 112750656eecSMasami Hiramatsu if (ptr) { 112850656eecSMasami Hiramatsu nc = *ptr; 112950656eecSMasami Hiramatsu *ptr++ = '\0'; 113050656eecSMasami Hiramatsu } 113150656eecSMasami Hiramatsu 113202b95dadSMasami Hiramatsu tmp = strdup(arg); 113302b95dadSMasami Hiramatsu if (tmp == NULL) 113402b95dadSMasami Hiramatsu return -ENOMEM; 113502b95dadSMasami Hiramatsu 113650656eecSMasami Hiramatsu /* Check arg is function or file and copy it */ 113702b95dadSMasami Hiramatsu if (strchr(tmp, '.')) /* File */ 113802b95dadSMasami Hiramatsu pp->file = tmp; 113950656eecSMasami Hiramatsu else /* Function */ 114002b95dadSMasami Hiramatsu pp->function = tmp; 114150656eecSMasami Hiramatsu 114250656eecSMasami Hiramatsu /* Parse other options */ 114350656eecSMasami Hiramatsu while (ptr) { 114450656eecSMasami Hiramatsu arg = ptr; 114550656eecSMasami Hiramatsu c = nc; 11462a9c8c36SMasami Hiramatsu if (c == ';') { /* Lazy pattern must be the last part */ 114702b95dadSMasami Hiramatsu pp->lazy_line = strdup(arg); 114802b95dadSMasami Hiramatsu if (pp->lazy_line == NULL) 114902b95dadSMasami Hiramatsu return -ENOMEM; 11502a9c8c36SMasami Hiramatsu break; 11512a9c8c36SMasami Hiramatsu } 11522a9c8c36SMasami Hiramatsu ptr = strpbrk(arg, ";:+@%"); 115350656eecSMasami Hiramatsu if (ptr) { 115450656eecSMasami Hiramatsu nc = *ptr; 115550656eecSMasami Hiramatsu *ptr++ = '\0'; 115650656eecSMasami Hiramatsu } 115750656eecSMasami Hiramatsu switch (c) { 115850656eecSMasami Hiramatsu case ':': /* Line number */ 115950656eecSMasami Hiramatsu pp->line = strtoul(arg, &tmp, 0); 1160146a1439SMasami Hiramatsu if (*tmp != '\0') { 11612a9c8c36SMasami Hiramatsu semantic_error("There is non-digit char" 1162146a1439SMasami Hiramatsu " in line number.\n"); 1163146a1439SMasami Hiramatsu return -EINVAL; 1164146a1439SMasami Hiramatsu } 116550656eecSMasami Hiramatsu break; 116650656eecSMasami Hiramatsu case '+': /* Byte offset from a symbol */ 116750656eecSMasami Hiramatsu pp->offset = strtoul(arg, &tmp, 0); 1168146a1439SMasami Hiramatsu if (*tmp != '\0') { 11692a9c8c36SMasami Hiramatsu semantic_error("There is non-digit character" 1170146a1439SMasami Hiramatsu " in offset.\n"); 1171146a1439SMasami Hiramatsu return -EINVAL; 1172146a1439SMasami Hiramatsu } 117350656eecSMasami Hiramatsu break; 117450656eecSMasami Hiramatsu case '@': /* File name */ 1175146a1439SMasami Hiramatsu if (pp->file) { 1176146a1439SMasami Hiramatsu semantic_error("SRC@SRC is not allowed.\n"); 1177146a1439SMasami Hiramatsu return -EINVAL; 1178146a1439SMasami Hiramatsu } 117902b95dadSMasami Hiramatsu pp->file = strdup(arg); 118002b95dadSMasami Hiramatsu if (pp->file == NULL) 118102b95dadSMasami Hiramatsu return -ENOMEM; 118250656eecSMasami Hiramatsu break; 118350656eecSMasami Hiramatsu case '%': /* Probe places */ 118450656eecSMasami Hiramatsu if (strcmp(arg, "return") == 0) { 118550656eecSMasami Hiramatsu pp->retprobe = 1; 1186146a1439SMasami Hiramatsu } else { /* Others not supported yet */ 1187146a1439SMasami Hiramatsu semantic_error("%%%s is not supported.\n", arg); 1188146a1439SMasami Hiramatsu return -ENOTSUP; 1189146a1439SMasami Hiramatsu } 119050656eecSMasami Hiramatsu break; 1191146a1439SMasami Hiramatsu default: /* Buggy case */ 1192146a1439SMasami Hiramatsu pr_err("This program has a bug at %s:%d.\n", 1193146a1439SMasami Hiramatsu __FILE__, __LINE__); 1194146a1439SMasami Hiramatsu return -ENOTSUP; 119550656eecSMasami Hiramatsu break; 119650656eecSMasami Hiramatsu } 119750656eecSMasami Hiramatsu } 119850656eecSMasami Hiramatsu 119950656eecSMasami Hiramatsu /* Exclusion check */ 1200146a1439SMasami Hiramatsu if (pp->lazy_line && pp->line) { 12010e43e5d2SMasami Hiramatsu semantic_error("Lazy pattern can't be used with" 12020e43e5d2SMasami Hiramatsu " line number.\n"); 1203146a1439SMasami Hiramatsu return -EINVAL; 1204146a1439SMasami Hiramatsu } 12052a9c8c36SMasami Hiramatsu 1206146a1439SMasami Hiramatsu if (pp->lazy_line && pp->offset) { 12070e43e5d2SMasami Hiramatsu semantic_error("Lazy pattern can't be used with offset.\n"); 1208146a1439SMasami Hiramatsu return -EINVAL; 1209146a1439SMasami Hiramatsu } 12102a9c8c36SMasami Hiramatsu 1211146a1439SMasami Hiramatsu if (pp->line && pp->offset) { 12120e43e5d2SMasami Hiramatsu semantic_error("Offset can't be used with line number.\n"); 1213146a1439SMasami Hiramatsu return -EINVAL; 1214146a1439SMasami Hiramatsu } 121550656eecSMasami Hiramatsu 1216146a1439SMasami Hiramatsu if (!pp->line && !pp->lazy_line && pp->file && !pp->function) { 12172a9c8c36SMasami Hiramatsu semantic_error("File always requires line number or " 12180e43e5d2SMasami Hiramatsu "lazy pattern.\n"); 1219146a1439SMasami Hiramatsu return -EINVAL; 1220146a1439SMasami Hiramatsu } 122150656eecSMasami Hiramatsu 1222146a1439SMasami Hiramatsu if (pp->offset && !pp->function) { 12230e43e5d2SMasami Hiramatsu semantic_error("Offset requires an entry function.\n"); 1224146a1439SMasami Hiramatsu return -EINVAL; 1225146a1439SMasami Hiramatsu } 122650656eecSMasami Hiramatsu 1227146a1439SMasami Hiramatsu if (pp->retprobe && !pp->function) { 12280e43e5d2SMasami Hiramatsu semantic_error("Return probe requires an entry function.\n"); 1229146a1439SMasami Hiramatsu return -EINVAL; 1230146a1439SMasami Hiramatsu } 123150656eecSMasami Hiramatsu 1232146a1439SMasami Hiramatsu if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { 12332a9c8c36SMasami Hiramatsu semantic_error("Offset/Line/Lazy pattern can't be used with " 12340e43e5d2SMasami Hiramatsu "return probe.\n"); 1235146a1439SMasami Hiramatsu return -EINVAL; 1236146a1439SMasami Hiramatsu } 123750656eecSMasami Hiramatsu 12384235b045SMasami Hiramatsu pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n", 12392a9c8c36SMasami Hiramatsu pp->function, pp->file, pp->line, pp->offset, pp->retprobe, 12402a9c8c36SMasami Hiramatsu pp->lazy_line); 1241146a1439SMasami Hiramatsu return 0; 124250656eecSMasami Hiramatsu } 124350656eecSMasami Hiramatsu 12447df2f329SMasami Hiramatsu /* Parse perf-probe event argument */ 1245146a1439SMasami Hiramatsu static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) 12467df2f329SMasami Hiramatsu { 1247b2a3c12bSMasami Hiramatsu char *tmp, *goodname; 12487df2f329SMasami Hiramatsu struct perf_probe_arg_field **fieldp; 12497df2f329SMasami Hiramatsu 12507df2f329SMasami Hiramatsu pr_debug("parsing arg: %s into ", str); 12517df2f329SMasami Hiramatsu 125248481938SMasami Hiramatsu tmp = strchr(str, '='); 125348481938SMasami Hiramatsu if (tmp) { 125402b95dadSMasami Hiramatsu arg->name = strndup(str, tmp - str); 125502b95dadSMasami Hiramatsu if (arg->name == NULL) 125602b95dadSMasami Hiramatsu return -ENOMEM; 125711a1ca35SMasami Hiramatsu pr_debug("name:%s ", arg->name); 125848481938SMasami Hiramatsu str = tmp + 1; 125948481938SMasami Hiramatsu } 126048481938SMasami Hiramatsu 126111a1ca35SMasami Hiramatsu tmp = strchr(str, ':'); 126211a1ca35SMasami Hiramatsu if (tmp) { /* Type setting */ 126311a1ca35SMasami Hiramatsu *tmp = '\0'; 126402b95dadSMasami Hiramatsu arg->type = strdup(tmp + 1); 126502b95dadSMasami Hiramatsu if (arg->type == NULL) 126602b95dadSMasami Hiramatsu return -ENOMEM; 126711a1ca35SMasami Hiramatsu pr_debug("type:%s ", arg->type); 126811a1ca35SMasami Hiramatsu } 126911a1ca35SMasami Hiramatsu 1270b2a3c12bSMasami Hiramatsu tmp = strpbrk(str, "-.["); 12717df2f329SMasami Hiramatsu if (!is_c_varname(str) || !tmp) { 12727df2f329SMasami Hiramatsu /* A variable, register, symbol or special value */ 127302b95dadSMasami Hiramatsu arg->var = strdup(str); 127402b95dadSMasami Hiramatsu if (arg->var == NULL) 127502b95dadSMasami Hiramatsu return -ENOMEM; 127648481938SMasami Hiramatsu pr_debug("%s\n", arg->var); 1277146a1439SMasami Hiramatsu return 0; 12787df2f329SMasami Hiramatsu } 12797df2f329SMasami Hiramatsu 1280b2a3c12bSMasami Hiramatsu /* Structure fields or array element */ 128102b95dadSMasami Hiramatsu arg->var = strndup(str, tmp - str); 128202b95dadSMasami Hiramatsu if (arg->var == NULL) 128302b95dadSMasami Hiramatsu return -ENOMEM; 1284b2a3c12bSMasami Hiramatsu goodname = arg->var; 128548481938SMasami Hiramatsu pr_debug("%s, ", arg->var); 12867df2f329SMasami Hiramatsu fieldp = &arg->field; 12877df2f329SMasami Hiramatsu 12887df2f329SMasami Hiramatsu do { 1289e334016fSMasami Hiramatsu *fieldp = zalloc(sizeof(struct perf_probe_arg_field)); 1290e334016fSMasami Hiramatsu if (*fieldp == NULL) 1291e334016fSMasami Hiramatsu return -ENOMEM; 1292b2a3c12bSMasami Hiramatsu if (*tmp == '[') { /* Array */ 1293b2a3c12bSMasami Hiramatsu str = tmp; 1294b2a3c12bSMasami Hiramatsu (*fieldp)->index = strtol(str + 1, &tmp, 0); 1295b2a3c12bSMasami Hiramatsu (*fieldp)->ref = true; 1296b2a3c12bSMasami Hiramatsu if (*tmp != ']' || tmp == str + 1) { 1297b2a3c12bSMasami Hiramatsu semantic_error("Array index must be a" 1298b2a3c12bSMasami Hiramatsu " number.\n"); 1299b2a3c12bSMasami Hiramatsu return -EINVAL; 1300b2a3c12bSMasami Hiramatsu } 1301b2a3c12bSMasami Hiramatsu tmp++; 1302b2a3c12bSMasami Hiramatsu if (*tmp == '\0') 1303b2a3c12bSMasami Hiramatsu tmp = NULL; 1304b2a3c12bSMasami Hiramatsu } else { /* Structure */ 13057df2f329SMasami Hiramatsu if (*tmp == '.') { 13067df2f329SMasami Hiramatsu str = tmp + 1; 13077df2f329SMasami Hiramatsu (*fieldp)->ref = false; 13087df2f329SMasami Hiramatsu } else if (tmp[1] == '>') { 13097df2f329SMasami Hiramatsu str = tmp + 2; 13107df2f329SMasami Hiramatsu (*fieldp)->ref = true; 1311146a1439SMasami Hiramatsu } else { 1312b2a3c12bSMasami Hiramatsu semantic_error("Argument parse error: %s\n", 1313b2a3c12bSMasami Hiramatsu str); 1314146a1439SMasami Hiramatsu return -EINVAL; 1315146a1439SMasami Hiramatsu } 1316b2a3c12bSMasami Hiramatsu tmp = strpbrk(str, "-.["); 1317b2a3c12bSMasami Hiramatsu } 13187df2f329SMasami Hiramatsu if (tmp) { 131902b95dadSMasami Hiramatsu (*fieldp)->name = strndup(str, tmp - str); 132002b95dadSMasami Hiramatsu if ((*fieldp)->name == NULL) 132102b95dadSMasami Hiramatsu return -ENOMEM; 1322b2a3c12bSMasami Hiramatsu if (*str != '[') 1323b2a3c12bSMasami Hiramatsu goodname = (*fieldp)->name; 13247df2f329SMasami Hiramatsu pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); 13257df2f329SMasami Hiramatsu fieldp = &(*fieldp)->next; 13267df2f329SMasami Hiramatsu } 13277df2f329SMasami Hiramatsu } while (tmp); 132802b95dadSMasami Hiramatsu (*fieldp)->name = strdup(str); 132902b95dadSMasami Hiramatsu if ((*fieldp)->name == NULL) 133002b95dadSMasami Hiramatsu return -ENOMEM; 1331b2a3c12bSMasami Hiramatsu if (*str != '[') 1332b2a3c12bSMasami Hiramatsu goodname = (*fieldp)->name; 13337df2f329SMasami Hiramatsu pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); 1334df0faf4bSMasami Hiramatsu 1335b2a3c12bSMasami Hiramatsu /* If no name is specified, set the last field name (not array index)*/ 133602b95dadSMasami Hiramatsu if (!arg->name) { 1337b2a3c12bSMasami Hiramatsu arg->name = strdup(goodname); 133802b95dadSMasami Hiramatsu if (arg->name == NULL) 133902b95dadSMasami Hiramatsu return -ENOMEM; 134002b95dadSMasami Hiramatsu } 1341146a1439SMasami Hiramatsu return 0; 13427df2f329SMasami Hiramatsu } 13437df2f329SMasami Hiramatsu 13444235b045SMasami Hiramatsu /* Parse perf-probe event command */ 1345146a1439SMasami Hiramatsu int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) 134650656eecSMasami Hiramatsu { 1347e1c01d61SMasami Hiramatsu char **argv; 1348146a1439SMasami Hiramatsu int argc, i, ret = 0; 1349fac13fd5SMasami Hiramatsu 13504235b045SMasami Hiramatsu argv = argv_split(cmd, &argc); 1351146a1439SMasami Hiramatsu if (!argv) { 1352146a1439SMasami Hiramatsu pr_debug("Failed to split arguments.\n"); 1353146a1439SMasami Hiramatsu return -ENOMEM; 1354146a1439SMasami Hiramatsu } 1355146a1439SMasami Hiramatsu if (argc - 1 > MAX_PROBE_ARGS) { 1356146a1439SMasami Hiramatsu semantic_error("Too many probe arguments (%d).\n", argc - 1); 1357146a1439SMasami Hiramatsu ret = -ERANGE; 1358146a1439SMasami Hiramatsu goto out; 1359146a1439SMasami Hiramatsu } 136050656eecSMasami Hiramatsu /* Parse probe point */ 1361146a1439SMasami Hiramatsu ret = parse_perf_probe_point(argv[0], pev); 1362146a1439SMasami Hiramatsu if (ret < 0) 1363146a1439SMasami Hiramatsu goto out; 136450656eecSMasami Hiramatsu 1365e1c01d61SMasami Hiramatsu /* Copy arguments and ensure return probe has no C argument */ 13664235b045SMasami Hiramatsu pev->nargs = argc - 1; 1367e334016fSMasami Hiramatsu pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); 1368e334016fSMasami Hiramatsu if (pev->args == NULL) { 1369e334016fSMasami Hiramatsu ret = -ENOMEM; 1370e334016fSMasami Hiramatsu goto out; 1371e334016fSMasami Hiramatsu } 1372146a1439SMasami Hiramatsu for (i = 0; i < pev->nargs && ret >= 0; i++) { 1373146a1439SMasami Hiramatsu ret = parse_perf_probe_arg(argv[i + 1], &pev->args[i]); 1374146a1439SMasami Hiramatsu if (ret >= 0 && 1375146a1439SMasami Hiramatsu is_c_varname(pev->args[i].var) && pev->point.retprobe) { 13764235b045SMasami Hiramatsu semantic_error("You can't specify local variable for" 1377146a1439SMasami Hiramatsu " kretprobe.\n"); 1378146a1439SMasami Hiramatsu ret = -EINVAL; 1379e1c01d61SMasami Hiramatsu } 1380146a1439SMasami Hiramatsu } 1381146a1439SMasami Hiramatsu out: 1382e1c01d61SMasami Hiramatsu argv_free(argv); 1383146a1439SMasami Hiramatsu 1384146a1439SMasami Hiramatsu return ret; 138550656eecSMasami Hiramatsu } 138650656eecSMasami Hiramatsu 13874235b045SMasami Hiramatsu /* Return true if this perf_probe_event requires debuginfo */ 13884235b045SMasami Hiramatsu bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) 13894de189feSMasami Hiramatsu { 13904235b045SMasami Hiramatsu int i; 13914235b045SMasami Hiramatsu 13924235b045SMasami Hiramatsu if (pev->point.file || pev->point.line || pev->point.lazy_line) 13934235b045SMasami Hiramatsu return true; 13944235b045SMasami Hiramatsu 13954235b045SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) 139648481938SMasami Hiramatsu if (is_c_varname(pev->args[i].var)) 13974235b045SMasami Hiramatsu return true; 13984235b045SMasami Hiramatsu 13994235b045SMasami Hiramatsu return false; 14004235b045SMasami Hiramatsu } 14014235b045SMasami Hiramatsu 14020e60836bSSrikar Dronamraju /* Parse probe_events event into struct probe_point */ 14030e60836bSSrikar Dronamraju static int parse_probe_trace_command(const char *cmd, 14040e60836bSSrikar Dronamraju struct probe_trace_event *tev) 14054235b045SMasami Hiramatsu { 14060e60836bSSrikar Dronamraju struct probe_trace_point *tp = &tev->point; 14074de189feSMasami Hiramatsu char pr; 14084de189feSMasami Hiramatsu char *p; 1409bcbd0040SIrina Tirdea char *argv0_str = NULL, *fmt, *fmt1_str, *fmt2_str, *fmt3_str; 14104de189feSMasami Hiramatsu int ret, i, argc; 14114de189feSMasami Hiramatsu char **argv; 14124de189feSMasami Hiramatsu 14130e60836bSSrikar Dronamraju pr_debug("Parsing probe_events: %s\n", cmd); 14144235b045SMasami Hiramatsu argv = argv_split(cmd, &argc); 1415146a1439SMasami Hiramatsu if (!argv) { 1416146a1439SMasami Hiramatsu pr_debug("Failed to split arguments.\n"); 1417146a1439SMasami Hiramatsu return -ENOMEM; 1418146a1439SMasami Hiramatsu } 1419146a1439SMasami Hiramatsu if (argc < 2) { 1420146a1439SMasami Hiramatsu semantic_error("Too few probe arguments.\n"); 1421146a1439SMasami Hiramatsu ret = -ERANGE; 1422146a1439SMasami Hiramatsu goto out; 1423146a1439SMasami Hiramatsu } 14244de189feSMasami Hiramatsu 14254de189feSMasami Hiramatsu /* Scan event and group name. */ 1426bcbd0040SIrina Tirdea argv0_str = strdup(argv[0]); 1427bcbd0040SIrina Tirdea if (argv0_str == NULL) { 1428bcbd0040SIrina Tirdea ret = -ENOMEM; 1429bcbd0040SIrina Tirdea goto out; 1430bcbd0040SIrina Tirdea } 1431bcbd0040SIrina Tirdea fmt1_str = strtok_r(argv0_str, ":", &fmt); 1432bcbd0040SIrina Tirdea fmt2_str = strtok_r(NULL, "/", &fmt); 1433bcbd0040SIrina Tirdea fmt3_str = strtok_r(NULL, " \t", &fmt); 1434bcbd0040SIrina Tirdea if (fmt1_str == NULL || strlen(fmt1_str) != 1 || fmt2_str == NULL 1435bcbd0040SIrina Tirdea || fmt3_str == NULL) { 1436146a1439SMasami Hiramatsu semantic_error("Failed to parse event name: %s\n", argv[0]); 1437146a1439SMasami Hiramatsu ret = -EINVAL; 1438146a1439SMasami Hiramatsu goto out; 1439146a1439SMasami Hiramatsu } 1440bcbd0040SIrina Tirdea pr = fmt1_str[0]; 1441bcbd0040SIrina Tirdea tev->group = strdup(fmt2_str); 1442bcbd0040SIrina Tirdea tev->event = strdup(fmt3_str); 1443bcbd0040SIrina Tirdea if (tev->group == NULL || tev->event == NULL) { 1444bcbd0040SIrina Tirdea ret = -ENOMEM; 1445bcbd0040SIrina Tirdea goto out; 1446bcbd0040SIrina Tirdea } 14474235b045SMasami Hiramatsu pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr); 14484de189feSMasami Hiramatsu 14494235b045SMasami Hiramatsu tp->retprobe = (pr == 'r'); 14504de189feSMasami Hiramatsu 1451190b57fcSMasami Hiramatsu /* Scan module name(if there), function name and offset */ 1452190b57fcSMasami Hiramatsu p = strchr(argv[1], ':'); 1453190b57fcSMasami Hiramatsu if (p) { 1454190b57fcSMasami Hiramatsu tp->module = strndup(argv[1], p - argv[1]); 1455190b57fcSMasami Hiramatsu p++; 1456190b57fcSMasami Hiramatsu } else 1457190b57fcSMasami Hiramatsu p = argv[1]; 1458bcbd0040SIrina Tirdea fmt1_str = strtok_r(p, "+", &fmt); 14595a6f6314SMasami Hiramatsu if (fmt1_str[0] == '0') /* only the address started with 0x */ 14605a6f6314SMasami Hiramatsu tp->address = strtoul(fmt1_str, NULL, 0); 14615a6f6314SMasami Hiramatsu else { 14625a6f6314SMasami Hiramatsu /* Only the symbol-based probe has offset */ 1463bcbd0040SIrina Tirdea tp->symbol = strdup(fmt1_str); 1464bcbd0040SIrina Tirdea if (tp->symbol == NULL) { 1465bcbd0040SIrina Tirdea ret = -ENOMEM; 1466bcbd0040SIrina Tirdea goto out; 1467bcbd0040SIrina Tirdea } 1468bcbd0040SIrina Tirdea fmt2_str = strtok_r(NULL, "", &fmt); 1469bcbd0040SIrina Tirdea if (fmt2_str == NULL) 14704235b045SMasami Hiramatsu tp->offset = 0; 1471bcbd0040SIrina Tirdea else 1472bcbd0040SIrina Tirdea tp->offset = strtoul(fmt2_str, NULL, 10); 14735a6f6314SMasami Hiramatsu } 14744de189feSMasami Hiramatsu 14754235b045SMasami Hiramatsu tev->nargs = argc - 2; 14760e60836bSSrikar Dronamraju tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); 1477e334016fSMasami Hiramatsu if (tev->args == NULL) { 1478e334016fSMasami Hiramatsu ret = -ENOMEM; 1479e334016fSMasami Hiramatsu goto out; 1480e334016fSMasami Hiramatsu } 14814235b045SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 14824de189feSMasami Hiramatsu p = strchr(argv[i + 2], '='); 14834de189feSMasami Hiramatsu if (p) /* We don't need which register is assigned. */ 14844235b045SMasami Hiramatsu *p++ = '\0'; 14854235b045SMasami Hiramatsu else 14864235b045SMasami Hiramatsu p = argv[i + 2]; 148702b95dadSMasami Hiramatsu tev->args[i].name = strdup(argv[i + 2]); 14884235b045SMasami Hiramatsu /* TODO: parse regs and offset */ 148902b95dadSMasami Hiramatsu tev->args[i].value = strdup(p); 149002b95dadSMasami Hiramatsu if (tev->args[i].name == NULL || tev->args[i].value == NULL) { 149102b95dadSMasami Hiramatsu ret = -ENOMEM; 149202b95dadSMasami Hiramatsu goto out; 149302b95dadSMasami Hiramatsu } 14944de189feSMasami Hiramatsu } 1495146a1439SMasami Hiramatsu ret = 0; 1496146a1439SMasami Hiramatsu out: 1497bcbd0040SIrina Tirdea free(argv0_str); 14984de189feSMasami Hiramatsu argv_free(argv); 1499146a1439SMasami Hiramatsu return ret; 15004de189feSMasami Hiramatsu } 15014de189feSMasami Hiramatsu 15027df2f329SMasami Hiramatsu /* Compose only probe arg */ 15037df2f329SMasami Hiramatsu int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) 15047df2f329SMasami Hiramatsu { 15057df2f329SMasami Hiramatsu struct perf_probe_arg_field *field = pa->field; 15067df2f329SMasami Hiramatsu int ret; 15077df2f329SMasami Hiramatsu char *tmp = buf; 15087df2f329SMasami Hiramatsu 150948481938SMasami Hiramatsu if (pa->name && pa->var) 151048481938SMasami Hiramatsu ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var); 151148481938SMasami Hiramatsu else 151248481938SMasami Hiramatsu ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var); 15137df2f329SMasami Hiramatsu if (ret <= 0) 15147df2f329SMasami Hiramatsu goto error; 15157df2f329SMasami Hiramatsu tmp += ret; 15167df2f329SMasami Hiramatsu len -= ret; 15177df2f329SMasami Hiramatsu 15187df2f329SMasami Hiramatsu while (field) { 1519b2a3c12bSMasami Hiramatsu if (field->name[0] == '[') 1520b2a3c12bSMasami Hiramatsu ret = e_snprintf(tmp, len, "%s", field->name); 1521b2a3c12bSMasami Hiramatsu else 1522b2a3c12bSMasami Hiramatsu ret = e_snprintf(tmp, len, "%s%s", 1523b2a3c12bSMasami Hiramatsu field->ref ? "->" : ".", field->name); 15247df2f329SMasami Hiramatsu if (ret <= 0) 15257df2f329SMasami Hiramatsu goto error; 15267df2f329SMasami Hiramatsu tmp += ret; 15277df2f329SMasami Hiramatsu len -= ret; 15287df2f329SMasami Hiramatsu field = field->next; 15297df2f329SMasami Hiramatsu } 153011a1ca35SMasami Hiramatsu 153111a1ca35SMasami Hiramatsu if (pa->type) { 153211a1ca35SMasami Hiramatsu ret = e_snprintf(tmp, len, ":%s", pa->type); 153311a1ca35SMasami Hiramatsu if (ret <= 0) 153411a1ca35SMasami Hiramatsu goto error; 153511a1ca35SMasami Hiramatsu tmp += ret; 153611a1ca35SMasami Hiramatsu len -= ret; 153711a1ca35SMasami Hiramatsu } 153811a1ca35SMasami Hiramatsu 15397df2f329SMasami Hiramatsu return tmp - buf; 15407df2f329SMasami Hiramatsu error: 15415f03cba4SMasami Hiramatsu pr_debug("Failed to synthesize perf probe argument: %d\n", ret); 1542146a1439SMasami Hiramatsu return ret; 15437df2f329SMasami Hiramatsu } 15447df2f329SMasami Hiramatsu 15454235b045SMasami Hiramatsu /* Compose only probe point (not argument) */ 15464235b045SMasami Hiramatsu static char *synthesize_perf_probe_point(struct perf_probe_point *pp) 154750656eecSMasami Hiramatsu { 1548fb1587d8SMasami Hiramatsu char *buf, *tmp; 1549fb1587d8SMasami Hiramatsu char offs[32] = "", line[32] = "", file[32] = ""; 1550fb1587d8SMasami Hiramatsu int ret, len; 155150656eecSMasami Hiramatsu 1552e334016fSMasami Hiramatsu buf = zalloc(MAX_CMDLEN); 1553e334016fSMasami Hiramatsu if (buf == NULL) { 1554e334016fSMasami Hiramatsu ret = -ENOMEM; 1555e334016fSMasami Hiramatsu goto error; 1556e334016fSMasami Hiramatsu } 15574de189feSMasami Hiramatsu if (pp->offset) { 1558fb1587d8SMasami Hiramatsu ret = e_snprintf(offs, 32, "+%lu", pp->offset); 15594de189feSMasami Hiramatsu if (ret <= 0) 15604de189feSMasami Hiramatsu goto error; 15614de189feSMasami Hiramatsu } 15624de189feSMasami Hiramatsu if (pp->line) { 1563fb1587d8SMasami Hiramatsu ret = e_snprintf(line, 32, ":%d", pp->line); 1564fb1587d8SMasami Hiramatsu if (ret <= 0) 1565fb1587d8SMasami Hiramatsu goto error; 1566fb1587d8SMasami Hiramatsu } 1567fb1587d8SMasami Hiramatsu if (pp->file) { 156832ae2adeSFranck Bui-Huu tmp = pp->file; 156932ae2adeSFranck Bui-Huu len = strlen(tmp); 157032ae2adeSFranck Bui-Huu if (len > 30) { 157132ae2adeSFranck Bui-Huu tmp = strchr(pp->file + len - 30, '/'); 157232ae2adeSFranck Bui-Huu tmp = tmp ? tmp + 1 : pp->file + len - 30; 157332ae2adeSFranck Bui-Huu } 157432ae2adeSFranck Bui-Huu ret = e_snprintf(file, 32, "@%s", tmp); 15754de189feSMasami Hiramatsu if (ret <= 0) 15764de189feSMasami Hiramatsu goto error; 15774de189feSMasami Hiramatsu } 15784de189feSMasami Hiramatsu 15794de189feSMasami Hiramatsu if (pp->function) 1580fb1587d8SMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function, 1581fb1587d8SMasami Hiramatsu offs, pp->retprobe ? "%return" : "", line, 1582fb1587d8SMasami Hiramatsu file); 15834de189feSMasami Hiramatsu else 1584fb1587d8SMasami Hiramatsu ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line); 15854235b045SMasami Hiramatsu if (ret <= 0) 15864235b045SMasami Hiramatsu goto error; 15874235b045SMasami Hiramatsu 15884235b045SMasami Hiramatsu return buf; 15894235b045SMasami Hiramatsu error: 15905f03cba4SMasami Hiramatsu pr_debug("Failed to synthesize perf probe point: %d\n", ret); 1591146a1439SMasami Hiramatsu free(buf); 1592146a1439SMasami Hiramatsu return NULL; 15934235b045SMasami Hiramatsu } 15944235b045SMasami Hiramatsu 15954235b045SMasami Hiramatsu #if 0 15964235b045SMasami Hiramatsu char *synthesize_perf_probe_command(struct perf_probe_event *pev) 15974235b045SMasami Hiramatsu { 15984235b045SMasami Hiramatsu char *buf; 15994235b045SMasami Hiramatsu int i, len, ret; 16004235b045SMasami Hiramatsu 16014235b045SMasami Hiramatsu buf = synthesize_perf_probe_point(&pev->point); 16024235b045SMasami Hiramatsu if (!buf) 16034235b045SMasami Hiramatsu return NULL; 16044235b045SMasami Hiramatsu 16054235b045SMasami Hiramatsu len = strlen(buf); 16064235b045SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) { 16074235b045SMasami Hiramatsu ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", 16084235b045SMasami Hiramatsu pev->args[i].name); 16097ef17aafSMasami Hiramatsu if (ret <= 0) { 16104235b045SMasami Hiramatsu free(buf); 16114235b045SMasami Hiramatsu return NULL; 16127ef17aafSMasami Hiramatsu } 16134235b045SMasami Hiramatsu len += ret; 16147ef17aafSMasami Hiramatsu } 161550656eecSMasami Hiramatsu 16164235b045SMasami Hiramatsu return buf; 16174235b045SMasami Hiramatsu } 16184235b045SMasami Hiramatsu #endif 16194235b045SMasami Hiramatsu 16200e60836bSSrikar Dronamraju static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, 16214235b045SMasami Hiramatsu char **buf, size_t *buflen, 16224235b045SMasami Hiramatsu int depth) 16237ef17aafSMasami Hiramatsu { 16244235b045SMasami Hiramatsu int ret; 16254235b045SMasami Hiramatsu if (ref->next) { 16260e60836bSSrikar Dronamraju depth = __synthesize_probe_trace_arg_ref(ref->next, buf, 16274235b045SMasami Hiramatsu buflen, depth + 1); 16284235b045SMasami Hiramatsu if (depth < 0) 16294235b045SMasami Hiramatsu goto out; 16304235b045SMasami Hiramatsu } 16314235b045SMasami Hiramatsu 16324235b045SMasami Hiramatsu ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset); 16334235b045SMasami Hiramatsu if (ret < 0) 16344235b045SMasami Hiramatsu depth = ret; 16354235b045SMasami Hiramatsu else { 16364235b045SMasami Hiramatsu *buf += ret; 16374235b045SMasami Hiramatsu *buflen -= ret; 16384235b045SMasami Hiramatsu } 16394235b045SMasami Hiramatsu out: 16404235b045SMasami Hiramatsu return depth; 16414235b045SMasami Hiramatsu 16424235b045SMasami Hiramatsu } 16434235b045SMasami Hiramatsu 16440e60836bSSrikar Dronamraju static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, 16454235b045SMasami Hiramatsu char *buf, size_t buflen) 16464235b045SMasami Hiramatsu { 16470e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref = arg->ref; 16484235b045SMasami Hiramatsu int ret, depth = 0; 16494235b045SMasami Hiramatsu char *tmp = buf; 16504235b045SMasami Hiramatsu 16514235b045SMasami Hiramatsu /* Argument name or separator */ 16524235b045SMasami Hiramatsu if (arg->name) 16534235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, " %s=", arg->name); 16544235b045SMasami Hiramatsu else 16554235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, " "); 16564235b045SMasami Hiramatsu if (ret < 0) 16574235b045SMasami Hiramatsu return ret; 16584235b045SMasami Hiramatsu buf += ret; 16594235b045SMasami Hiramatsu buflen -= ret; 16604235b045SMasami Hiramatsu 1661b7dcb857SMasami Hiramatsu /* Special case: @XXX */ 1662b7dcb857SMasami Hiramatsu if (arg->value[0] == '@' && arg->ref) 1663b7dcb857SMasami Hiramatsu ref = ref->next; 1664b7dcb857SMasami Hiramatsu 16654235b045SMasami Hiramatsu /* Dereferencing arguments */ 1666b7dcb857SMasami Hiramatsu if (ref) { 16670e60836bSSrikar Dronamraju depth = __synthesize_probe_trace_arg_ref(ref, &buf, 16684235b045SMasami Hiramatsu &buflen, 1); 16694235b045SMasami Hiramatsu if (depth < 0) 16704235b045SMasami Hiramatsu return depth; 16714235b045SMasami Hiramatsu } 16724235b045SMasami Hiramatsu 16734235b045SMasami Hiramatsu /* Print argument value */ 1674b7dcb857SMasami Hiramatsu if (arg->value[0] == '@' && arg->ref) 1675b7dcb857SMasami Hiramatsu ret = e_snprintf(buf, buflen, "%s%+ld", arg->value, 1676b7dcb857SMasami Hiramatsu arg->ref->offset); 1677b7dcb857SMasami Hiramatsu else 16784235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, "%s", arg->value); 16794235b045SMasami Hiramatsu if (ret < 0) 16804235b045SMasami Hiramatsu return ret; 16814235b045SMasami Hiramatsu buf += ret; 16824235b045SMasami Hiramatsu buflen -= ret; 16834235b045SMasami Hiramatsu 16844235b045SMasami Hiramatsu /* Closing */ 16854235b045SMasami Hiramatsu while (depth--) { 16864235b045SMasami Hiramatsu ret = e_snprintf(buf, buflen, ")"); 16874235b045SMasami Hiramatsu if (ret < 0) 16884235b045SMasami Hiramatsu return ret; 16894235b045SMasami Hiramatsu buf += ret; 16904235b045SMasami Hiramatsu buflen -= ret; 16914235b045SMasami Hiramatsu } 16924984912eSMasami Hiramatsu /* Print argument type */ 16934984912eSMasami Hiramatsu if (arg->type) { 16944984912eSMasami Hiramatsu ret = e_snprintf(buf, buflen, ":%s", arg->type); 16954984912eSMasami Hiramatsu if (ret <= 0) 16964984912eSMasami Hiramatsu return ret; 16974984912eSMasami Hiramatsu buf += ret; 16984984912eSMasami Hiramatsu } 16994235b045SMasami Hiramatsu 17004235b045SMasami Hiramatsu return buf - tmp; 17014235b045SMasami Hiramatsu } 17024235b045SMasami Hiramatsu 17030e60836bSSrikar Dronamraju char *synthesize_probe_trace_command(struct probe_trace_event *tev) 17044235b045SMasami Hiramatsu { 17050e60836bSSrikar Dronamraju struct probe_trace_point *tp = &tev->point; 17067ef17aafSMasami Hiramatsu char *buf; 17077ef17aafSMasami Hiramatsu int i, len, ret; 17087ef17aafSMasami Hiramatsu 1709e334016fSMasami Hiramatsu buf = zalloc(MAX_CMDLEN); 1710e334016fSMasami Hiramatsu if (buf == NULL) 1711e334016fSMasami Hiramatsu return NULL; 1712e334016fSMasami Hiramatsu 1713eb948e50SMasami Hiramatsu len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p', 1714eb948e50SMasami Hiramatsu tev->group, tev->event); 1715eb948e50SMasami Hiramatsu if (len <= 0) 1716eb948e50SMasami Hiramatsu goto error; 1717eb948e50SMasami Hiramatsu 1718eb948e50SMasami Hiramatsu /* Uprobes must have tp->address and tp->module */ 1719eb948e50SMasami Hiramatsu if (tev->uprobes && (!tp->address || !tp->module)) 1720eb948e50SMasami Hiramatsu goto error; 1721eb948e50SMasami Hiramatsu 1722eb948e50SMasami Hiramatsu /* Use the tp->address for uprobes */ 1723225466f1SSrikar Dronamraju if (tev->uprobes) 1724eb948e50SMasami Hiramatsu ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx", 1725eb948e50SMasami Hiramatsu tp->module, tp->address); 1726225466f1SSrikar Dronamraju else 1727eb948e50SMasami Hiramatsu ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu", 1728190b57fcSMasami Hiramatsu tp->module ?: "", tp->module ? ":" : "", 17294235b045SMasami Hiramatsu tp->symbol, tp->offset); 1730225466f1SSrikar Dronamraju 1731eb948e50SMasami Hiramatsu if (ret <= 0) 17324235b045SMasami Hiramatsu goto error; 1733eb948e50SMasami Hiramatsu len += ret; 17347ef17aafSMasami Hiramatsu 17354235b045SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 17360e60836bSSrikar Dronamraju ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, 17374235b045SMasami Hiramatsu MAX_CMDLEN - len); 17384de189feSMasami Hiramatsu if (ret <= 0) 173950656eecSMasami Hiramatsu goto error; 174050656eecSMasami Hiramatsu len += ret; 174150656eecSMasami Hiramatsu } 174250656eecSMasami Hiramatsu 17434235b045SMasami Hiramatsu return buf; 174450656eecSMasami Hiramatsu error: 17454235b045SMasami Hiramatsu free(buf); 17464235b045SMasami Hiramatsu return NULL; 174750656eecSMasami Hiramatsu } 174850656eecSMasami Hiramatsu 17495a6f6314SMasami Hiramatsu static int find_perf_probe_point_from_map(struct probe_trace_point *tp, 17505a6f6314SMasami Hiramatsu struct perf_probe_point *pp, 17515a6f6314SMasami Hiramatsu bool is_kprobe) 17525a6f6314SMasami Hiramatsu { 17535a6f6314SMasami Hiramatsu struct symbol *sym = NULL; 17545a6f6314SMasami Hiramatsu struct map *map; 17555a6f6314SMasami Hiramatsu u64 addr; 17565a6f6314SMasami Hiramatsu int ret = -ENOENT; 17575a6f6314SMasami Hiramatsu 17585a6f6314SMasami Hiramatsu if (!is_kprobe) { 17595a6f6314SMasami Hiramatsu map = dso__new_map(tp->module); 17605a6f6314SMasami Hiramatsu if (!map) 17615a6f6314SMasami Hiramatsu goto out; 17625a6f6314SMasami Hiramatsu addr = tp->address; 17635a6f6314SMasami Hiramatsu sym = map__find_symbol(map, addr, NULL); 17645a6f6314SMasami Hiramatsu } else { 17655a6f6314SMasami Hiramatsu addr = kernel_get_symbol_address_by_name(tp->symbol, true); 17665a6f6314SMasami Hiramatsu if (addr) { 17675a6f6314SMasami Hiramatsu addr += tp->offset; 17685a6f6314SMasami Hiramatsu sym = __find_kernel_function(addr, &map); 17695a6f6314SMasami Hiramatsu } 17705a6f6314SMasami Hiramatsu } 17715a6f6314SMasami Hiramatsu if (!sym) 17725a6f6314SMasami Hiramatsu goto out; 17735a6f6314SMasami Hiramatsu 17745a6f6314SMasami Hiramatsu pp->retprobe = tp->retprobe; 17755a6f6314SMasami Hiramatsu pp->offset = addr - map->unmap_ip(map, sym->start); 17765a6f6314SMasami Hiramatsu pp->function = strdup(sym->name); 17775a6f6314SMasami Hiramatsu ret = pp->function ? 0 : -ENOMEM; 17785a6f6314SMasami Hiramatsu 17795a6f6314SMasami Hiramatsu out: 17805a6f6314SMasami Hiramatsu if (map && !is_kprobe) { 17815a6f6314SMasami Hiramatsu dso__delete(map->dso); 17825a6f6314SMasami Hiramatsu map__delete(map); 17835a6f6314SMasami Hiramatsu } 17845a6f6314SMasami Hiramatsu 17855a6f6314SMasami Hiramatsu return ret; 17865a6f6314SMasami Hiramatsu } 17875a6f6314SMasami Hiramatsu 17885a6f6314SMasami Hiramatsu static int convert_to_perf_probe_point(struct probe_trace_point *tp, 17895a6f6314SMasami Hiramatsu struct perf_probe_point *pp, 17905a6f6314SMasami Hiramatsu bool is_kprobe) 17915a6f6314SMasami Hiramatsu { 17925a6f6314SMasami Hiramatsu char buf[128]; 17935a6f6314SMasami Hiramatsu int ret; 17945a6f6314SMasami Hiramatsu 17955a6f6314SMasami Hiramatsu ret = find_perf_probe_point_from_dwarf(tp, pp, is_kprobe); 17965a6f6314SMasami Hiramatsu if (!ret) 17975a6f6314SMasami Hiramatsu return 0; 17985a6f6314SMasami Hiramatsu ret = find_perf_probe_point_from_map(tp, pp, is_kprobe); 17995a6f6314SMasami Hiramatsu if (!ret) 18005a6f6314SMasami Hiramatsu return 0; 18015a6f6314SMasami Hiramatsu 18025a6f6314SMasami Hiramatsu pr_debug("Failed to find probe point from both of dwarf and map.\n"); 18035a6f6314SMasami Hiramatsu 18045a6f6314SMasami Hiramatsu if (tp->symbol) { 18055a6f6314SMasami Hiramatsu pp->function = strdup(tp->symbol); 18065a6f6314SMasami Hiramatsu pp->offset = tp->offset; 18075a6f6314SMasami Hiramatsu } else if (!tp->module && !is_kprobe) { 18085a6f6314SMasami Hiramatsu ret = e_snprintf(buf, 128, "0x%" PRIx64, (u64)tp->address); 18095a6f6314SMasami Hiramatsu if (ret < 0) 18105a6f6314SMasami Hiramatsu return ret; 18115a6f6314SMasami Hiramatsu pp->function = strdup(buf); 18125a6f6314SMasami Hiramatsu pp->offset = 0; 18135a6f6314SMasami Hiramatsu } 18145a6f6314SMasami Hiramatsu if (pp->function == NULL) 18155a6f6314SMasami Hiramatsu return -ENOMEM; 18165a6f6314SMasami Hiramatsu 18175a6f6314SMasami Hiramatsu pp->retprobe = tp->retprobe; 18185a6f6314SMasami Hiramatsu 18195a6f6314SMasami Hiramatsu return 0; 18205a6f6314SMasami Hiramatsu } 18215a6f6314SMasami Hiramatsu 18220e60836bSSrikar Dronamraju static int convert_to_perf_probe_event(struct probe_trace_event *tev, 1823225466f1SSrikar Dronamraju struct perf_probe_event *pev, bool is_kprobe) 18244de189feSMasami Hiramatsu { 182502b95dadSMasami Hiramatsu char buf[64] = ""; 1826146a1439SMasami Hiramatsu int i, ret; 18274de189feSMasami Hiramatsu 18284b4da7f7SMasami Hiramatsu /* Convert event/group name */ 182902b95dadSMasami Hiramatsu pev->event = strdup(tev->event); 183002b95dadSMasami Hiramatsu pev->group = strdup(tev->group); 183102b95dadSMasami Hiramatsu if (pev->event == NULL || pev->group == NULL) 183202b95dadSMasami Hiramatsu return -ENOMEM; 1833fb1587d8SMasami Hiramatsu 18344b4da7f7SMasami Hiramatsu /* Convert trace_point to probe_point */ 18355a6f6314SMasami Hiramatsu ret = convert_to_perf_probe_point(&tev->point, &pev->point, is_kprobe); 1836146a1439SMasami Hiramatsu if (ret < 0) 1837146a1439SMasami Hiramatsu return ret; 18384b4da7f7SMasami Hiramatsu 18394235b045SMasami Hiramatsu /* Convert trace_arg to probe_arg */ 18404235b045SMasami Hiramatsu pev->nargs = tev->nargs; 1841e334016fSMasami Hiramatsu pev->args = zalloc(sizeof(struct perf_probe_arg) * pev->nargs); 1842e334016fSMasami Hiramatsu if (pev->args == NULL) 1843e334016fSMasami Hiramatsu return -ENOMEM; 184402b95dadSMasami Hiramatsu for (i = 0; i < tev->nargs && ret >= 0; i++) { 18454235b045SMasami Hiramatsu if (tev->args[i].name) 184602b95dadSMasami Hiramatsu pev->args[i].name = strdup(tev->args[i].name); 18474235b045SMasami Hiramatsu else { 18480e60836bSSrikar Dronamraju ret = synthesize_probe_trace_arg(&tev->args[i], 1849146a1439SMasami Hiramatsu buf, 64); 185002b95dadSMasami Hiramatsu pev->args[i].name = strdup(buf); 185102b95dadSMasami Hiramatsu } 185202b95dadSMasami Hiramatsu if (pev->args[i].name == NULL && ret >= 0) 185302b95dadSMasami Hiramatsu ret = -ENOMEM; 18544de189feSMasami Hiramatsu } 1855146a1439SMasami Hiramatsu 1856146a1439SMasami Hiramatsu if (ret < 0) 1857146a1439SMasami Hiramatsu clear_perf_probe_event(pev); 1858146a1439SMasami Hiramatsu 1859146a1439SMasami Hiramatsu return ret; 18604235b045SMasami Hiramatsu } 18614de189feSMasami Hiramatsu 18624235b045SMasami Hiramatsu void clear_perf_probe_event(struct perf_probe_event *pev) 18634235b045SMasami Hiramatsu { 18647df2f329SMasami Hiramatsu struct perf_probe_arg_field *field, *next; 18654235b045SMasami Hiramatsu int i; 18664de189feSMasami Hiramatsu 18674235b045SMasami Hiramatsu free(pev->event); 18684235b045SMasami Hiramatsu free(pev->group); 1869*9b118acaSMasami Hiramatsu clear_perf_probe_point(&pev->point); 1870f5385650SArnaldo Carvalho de Melo 18717df2f329SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) { 18724235b045SMasami Hiramatsu free(pev->args[i].name); 187348481938SMasami Hiramatsu free(pev->args[i].var); 187411a1ca35SMasami Hiramatsu free(pev->args[i].type); 18757df2f329SMasami Hiramatsu field = pev->args[i].field; 18767df2f329SMasami Hiramatsu while (field) { 18777df2f329SMasami Hiramatsu next = field->next; 187874cf249dSArnaldo Carvalho de Melo zfree(&field->name); 18797df2f329SMasami Hiramatsu free(field); 18807df2f329SMasami Hiramatsu field = next; 18817df2f329SMasami Hiramatsu } 18827df2f329SMasami Hiramatsu } 18834235b045SMasami Hiramatsu free(pev->args); 18844235b045SMasami Hiramatsu memset(pev, 0, sizeof(*pev)); 18854235b045SMasami Hiramatsu } 18864235b045SMasami Hiramatsu 18870e60836bSSrikar Dronamraju static void clear_probe_trace_event(struct probe_trace_event *tev) 18884235b045SMasami Hiramatsu { 18890e60836bSSrikar Dronamraju struct probe_trace_arg_ref *ref, *next; 18904235b045SMasami Hiramatsu int i; 18914235b045SMasami Hiramatsu 18924235b045SMasami Hiramatsu free(tev->event); 18934235b045SMasami Hiramatsu free(tev->group); 18944235b045SMasami Hiramatsu free(tev->point.symbol); 1895190b57fcSMasami Hiramatsu free(tev->point.module); 18964235b045SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 18974235b045SMasami Hiramatsu free(tev->args[i].name); 18984235b045SMasami Hiramatsu free(tev->args[i].value); 18994984912eSMasami Hiramatsu free(tev->args[i].type); 19004235b045SMasami Hiramatsu ref = tev->args[i].ref; 19014235b045SMasami Hiramatsu while (ref) { 19024235b045SMasami Hiramatsu next = ref->next; 19034235b045SMasami Hiramatsu free(ref); 19044235b045SMasami Hiramatsu ref = next; 19054235b045SMasami Hiramatsu } 19064235b045SMasami Hiramatsu } 19074235b045SMasami Hiramatsu free(tev->args); 19084235b045SMasami Hiramatsu memset(tev, 0, sizeof(*tev)); 19094de189feSMasami Hiramatsu } 19104de189feSMasami Hiramatsu 19115e45187cSMasami Hiramatsu static void print_open_warning(int err, bool is_kprobe) 1912225466f1SSrikar Dronamraju { 19135f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 1914225466f1SSrikar Dronamraju 19155e45187cSMasami Hiramatsu if (err == -ENOENT) { 1916225466f1SSrikar Dronamraju const char *config; 1917225466f1SSrikar Dronamraju 1918225466f1SSrikar Dronamraju if (!is_kprobe) 1919225466f1SSrikar Dronamraju config = "CONFIG_UPROBE_EVENTS"; 1920225466f1SSrikar Dronamraju else 1921225466f1SSrikar Dronamraju config = "CONFIG_KPROBE_EVENTS"; 1922225466f1SSrikar Dronamraju 19235e45187cSMasami Hiramatsu pr_warning("%cprobe_events file does not exist" 19245e45187cSMasami Hiramatsu " - please rebuild kernel with %s.\n", 19255e45187cSMasami Hiramatsu is_kprobe ? 'k' : 'u', config); 19265e45187cSMasami Hiramatsu } else if (err == -ENOTSUP) 192723773ca1SSteven Rostedt (Red Hat) pr_warning("Tracefs or debugfs is not mounted.\n"); 19285e45187cSMasami Hiramatsu else 19295e45187cSMasami Hiramatsu pr_warning("Failed to open %cprobe_events: %s\n", 19305e45187cSMasami Hiramatsu is_kprobe ? 'k' : 'u', 19315e45187cSMasami Hiramatsu strerror_r(-err, sbuf, sizeof(sbuf))); 1932225466f1SSrikar Dronamraju } 1933225466f1SSrikar Dronamraju 1934467ec085SMasami Hiramatsu static void print_both_open_warning(int kerr, int uerr) 1935467ec085SMasami Hiramatsu { 1936467ec085SMasami Hiramatsu /* Both kprobes and uprobes are disabled, warn it. */ 1937467ec085SMasami Hiramatsu if (kerr == -ENOTSUP && uerr == -ENOTSUP) 193823773ca1SSteven Rostedt (Red Hat) pr_warning("Tracefs or debugfs is not mounted.\n"); 1939467ec085SMasami Hiramatsu else if (kerr == -ENOENT && uerr == -ENOENT) 1940467ec085SMasami Hiramatsu pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS " 1941467ec085SMasami Hiramatsu "or/and CONFIG_UPROBE_EVENTS.\n"); 1942467ec085SMasami Hiramatsu else { 19435f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 1944467ec085SMasami Hiramatsu pr_warning("Failed to open kprobe events: %s.\n", 1945467ec085SMasami Hiramatsu strerror_r(-kerr, sbuf, sizeof(sbuf))); 1946467ec085SMasami Hiramatsu pr_warning("Failed to open uprobe events: %s.\n", 1947467ec085SMasami Hiramatsu strerror_r(-uerr, sbuf, sizeof(sbuf))); 1948467ec085SMasami Hiramatsu } 1949467ec085SMasami Hiramatsu } 1950467ec085SMasami Hiramatsu 19515e45187cSMasami Hiramatsu static int open_probe_events(const char *trace_file, bool readwrite) 19524de189feSMasami Hiramatsu { 19534de189feSMasami Hiramatsu char buf[PATH_MAX]; 19547ca5989dSMasami Hiramatsu const char *__debugfs; 195523773ca1SSteven Rostedt (Red Hat) const char *tracing_dir = ""; 19564de189feSMasami Hiramatsu int ret; 19574de189feSMasami Hiramatsu 195823773ca1SSteven Rostedt (Red Hat) __debugfs = tracefs_find_mountpoint(); 195923773ca1SSteven Rostedt (Red Hat) if (__debugfs == NULL) { 196023773ca1SSteven Rostedt (Red Hat) tracing_dir = "tracing/"; 196123773ca1SSteven Rostedt (Red Hat) 19627ca5989dSMasami Hiramatsu __debugfs = debugfs_find_mountpoint(); 19635e45187cSMasami Hiramatsu if (__debugfs == NULL) 19645e45187cSMasami Hiramatsu return -ENOTSUP; 196523773ca1SSteven Rostedt (Red Hat) } 19667ca5989dSMasami Hiramatsu 196723773ca1SSteven Rostedt (Red Hat) ret = e_snprintf(buf, PATH_MAX, "%s/%s%s", 196823773ca1SSteven Rostedt (Red Hat) __debugfs, tracing_dir, trace_file); 1969146a1439SMasami Hiramatsu if (ret >= 0) { 19707ca5989dSMasami Hiramatsu pr_debug("Opening %s write=%d\n", buf, readwrite); 1971f4d7da49SMasami Hiramatsu if (readwrite && !probe_event_dry_run) 1972f4d7da49SMasami Hiramatsu ret = open(buf, O_RDWR, O_APPEND); 1973f4d7da49SMasami Hiramatsu else 1974f4d7da49SMasami Hiramatsu ret = open(buf, O_RDONLY, 0); 1975f4d7da49SMasami Hiramatsu 1976225466f1SSrikar Dronamraju if (ret < 0) 19775e45187cSMasami Hiramatsu ret = -errno; 19784de189feSMasami Hiramatsu } 19794de189feSMasami Hiramatsu return ret; 19804de189feSMasami Hiramatsu } 19814de189feSMasami Hiramatsu 1982225466f1SSrikar Dronamraju static int open_kprobe_events(bool readwrite) 1983225466f1SSrikar Dronamraju { 198423773ca1SSteven Rostedt (Red Hat) return open_probe_events("kprobe_events", readwrite); 1985225466f1SSrikar Dronamraju } 1986225466f1SSrikar Dronamraju 1987225466f1SSrikar Dronamraju static int open_uprobe_events(bool readwrite) 1988225466f1SSrikar Dronamraju { 198923773ca1SSteven Rostedt (Red Hat) return open_probe_events("uprobe_events", readwrite); 1990225466f1SSrikar Dronamraju } 1991225466f1SSrikar Dronamraju 1992225466f1SSrikar Dronamraju /* Get raw string list of current kprobe_events or uprobe_events */ 19930e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_command_rawlist(int fd) 19944de189feSMasami Hiramatsu { 19954de189feSMasami Hiramatsu int ret, idx; 19964de189feSMasami Hiramatsu FILE *fp; 19974de189feSMasami Hiramatsu char buf[MAX_CMDLEN]; 19984de189feSMasami Hiramatsu char *p; 19994de189feSMasami Hiramatsu struct strlist *sl; 20004de189feSMasami Hiramatsu 20014de189feSMasami Hiramatsu sl = strlist__new(true, NULL); 20024de189feSMasami Hiramatsu 20034de189feSMasami Hiramatsu fp = fdopen(dup(fd), "r"); 20044de189feSMasami Hiramatsu while (!feof(fp)) { 20054de189feSMasami Hiramatsu p = fgets(buf, MAX_CMDLEN, fp); 20064de189feSMasami Hiramatsu if (!p) 20074de189feSMasami Hiramatsu break; 20084de189feSMasami Hiramatsu 20094de189feSMasami Hiramatsu idx = strlen(p) - 1; 20104de189feSMasami Hiramatsu if (p[idx] == '\n') 20114de189feSMasami Hiramatsu p[idx] = '\0'; 20124de189feSMasami Hiramatsu ret = strlist__add(sl, buf); 2013146a1439SMasami Hiramatsu if (ret < 0) { 20146eb08660SMasami Hiramatsu pr_debug("strlist__add failed (%d)\n", ret); 2015146a1439SMasami Hiramatsu strlist__delete(sl); 2016146a1439SMasami Hiramatsu return NULL; 2017146a1439SMasami Hiramatsu } 20184de189feSMasami Hiramatsu } 20194de189feSMasami Hiramatsu fclose(fp); 20204de189feSMasami Hiramatsu 20214de189feSMasami Hiramatsu return sl; 20224de189feSMasami Hiramatsu } 20234de189feSMasami Hiramatsu 20249aaf5a5fSMasami Hiramatsu struct kprobe_blacklist_node { 20259aaf5a5fSMasami Hiramatsu struct list_head list; 20269aaf5a5fSMasami Hiramatsu unsigned long start; 20279aaf5a5fSMasami Hiramatsu unsigned long end; 20289aaf5a5fSMasami Hiramatsu char *symbol; 20299aaf5a5fSMasami Hiramatsu }; 20309aaf5a5fSMasami Hiramatsu 20319aaf5a5fSMasami Hiramatsu static void kprobe_blacklist__delete(struct list_head *blacklist) 20329aaf5a5fSMasami Hiramatsu { 20339aaf5a5fSMasami Hiramatsu struct kprobe_blacklist_node *node; 20349aaf5a5fSMasami Hiramatsu 20359aaf5a5fSMasami Hiramatsu while (!list_empty(blacklist)) { 20369aaf5a5fSMasami Hiramatsu node = list_first_entry(blacklist, 20379aaf5a5fSMasami Hiramatsu struct kprobe_blacklist_node, list); 20389aaf5a5fSMasami Hiramatsu list_del(&node->list); 20399aaf5a5fSMasami Hiramatsu free(node->symbol); 20409aaf5a5fSMasami Hiramatsu free(node); 20419aaf5a5fSMasami Hiramatsu } 20429aaf5a5fSMasami Hiramatsu } 20439aaf5a5fSMasami Hiramatsu 20449aaf5a5fSMasami Hiramatsu static int kprobe_blacklist__load(struct list_head *blacklist) 20459aaf5a5fSMasami Hiramatsu { 20469aaf5a5fSMasami Hiramatsu struct kprobe_blacklist_node *node; 20479aaf5a5fSMasami Hiramatsu const char *__debugfs = debugfs_find_mountpoint(); 20489aaf5a5fSMasami Hiramatsu char buf[PATH_MAX], *p; 20499aaf5a5fSMasami Hiramatsu FILE *fp; 20509aaf5a5fSMasami Hiramatsu int ret; 20519aaf5a5fSMasami Hiramatsu 20529aaf5a5fSMasami Hiramatsu if (__debugfs == NULL) 20539aaf5a5fSMasami Hiramatsu return -ENOTSUP; 20549aaf5a5fSMasami Hiramatsu 20559aaf5a5fSMasami Hiramatsu ret = e_snprintf(buf, PATH_MAX, "%s/kprobes/blacklist", __debugfs); 20569aaf5a5fSMasami Hiramatsu if (ret < 0) 20579aaf5a5fSMasami Hiramatsu return ret; 20589aaf5a5fSMasami Hiramatsu 20599aaf5a5fSMasami Hiramatsu fp = fopen(buf, "r"); 20609aaf5a5fSMasami Hiramatsu if (!fp) 20619aaf5a5fSMasami Hiramatsu return -errno; 20629aaf5a5fSMasami Hiramatsu 20639aaf5a5fSMasami Hiramatsu ret = 0; 20649aaf5a5fSMasami Hiramatsu while (fgets(buf, PATH_MAX, fp)) { 20659aaf5a5fSMasami Hiramatsu node = zalloc(sizeof(*node)); 20669aaf5a5fSMasami Hiramatsu if (!node) { 20679aaf5a5fSMasami Hiramatsu ret = -ENOMEM; 20689aaf5a5fSMasami Hiramatsu break; 20699aaf5a5fSMasami Hiramatsu } 20709aaf5a5fSMasami Hiramatsu INIT_LIST_HEAD(&node->list); 20719aaf5a5fSMasami Hiramatsu list_add_tail(&node->list, blacklist); 20729aaf5a5fSMasami Hiramatsu if (sscanf(buf, "0x%lx-0x%lx", &node->start, &node->end) != 2) { 20739aaf5a5fSMasami Hiramatsu ret = -EINVAL; 20749aaf5a5fSMasami Hiramatsu break; 20759aaf5a5fSMasami Hiramatsu } 20769aaf5a5fSMasami Hiramatsu p = strchr(buf, '\t'); 20779aaf5a5fSMasami Hiramatsu if (p) { 20789aaf5a5fSMasami Hiramatsu p++; 20799aaf5a5fSMasami Hiramatsu if (p[strlen(p) - 1] == '\n') 20809aaf5a5fSMasami Hiramatsu p[strlen(p) - 1] = '\0'; 20819aaf5a5fSMasami Hiramatsu } else 20829aaf5a5fSMasami Hiramatsu p = (char *)"unknown"; 20839aaf5a5fSMasami Hiramatsu node->symbol = strdup(p); 20849aaf5a5fSMasami Hiramatsu if (!node->symbol) { 20859aaf5a5fSMasami Hiramatsu ret = -ENOMEM; 20869aaf5a5fSMasami Hiramatsu break; 20879aaf5a5fSMasami Hiramatsu } 20889aaf5a5fSMasami Hiramatsu pr_debug2("Blacklist: 0x%lx-0x%lx, %s\n", 20899aaf5a5fSMasami Hiramatsu node->start, node->end, node->symbol); 20909aaf5a5fSMasami Hiramatsu ret++; 20919aaf5a5fSMasami Hiramatsu } 20929aaf5a5fSMasami Hiramatsu if (ret < 0) 20939aaf5a5fSMasami Hiramatsu kprobe_blacklist__delete(blacklist); 20949aaf5a5fSMasami Hiramatsu fclose(fp); 20959aaf5a5fSMasami Hiramatsu 20969aaf5a5fSMasami Hiramatsu return ret; 20979aaf5a5fSMasami Hiramatsu } 20989aaf5a5fSMasami Hiramatsu 20999aaf5a5fSMasami Hiramatsu static struct kprobe_blacklist_node * 21009aaf5a5fSMasami Hiramatsu kprobe_blacklist__find_by_address(struct list_head *blacklist, 21019aaf5a5fSMasami Hiramatsu unsigned long address) 21029aaf5a5fSMasami Hiramatsu { 21039aaf5a5fSMasami Hiramatsu struct kprobe_blacklist_node *node; 21049aaf5a5fSMasami Hiramatsu 21059aaf5a5fSMasami Hiramatsu list_for_each_entry(node, blacklist, list) { 21069aaf5a5fSMasami Hiramatsu if (node->start <= address && address <= node->end) 21079aaf5a5fSMasami Hiramatsu return node; 21089aaf5a5fSMasami Hiramatsu } 21099aaf5a5fSMasami Hiramatsu 21109aaf5a5fSMasami Hiramatsu return NULL; 21119aaf5a5fSMasami Hiramatsu } 21129aaf5a5fSMasami Hiramatsu 2113278498d4SMasami Hiramatsu /* Show an event */ 2114fb226ccdSMasami Hiramatsu static int show_perf_probe_event(struct perf_probe_event *pev, 2115fb226ccdSMasami Hiramatsu const char *module) 2116278498d4SMasami Hiramatsu { 21177e990a51SMasami Hiramatsu int i, ret; 2118278498d4SMasami Hiramatsu char buf[128]; 21194235b045SMasami Hiramatsu char *place; 2120278498d4SMasami Hiramatsu 21214235b045SMasami Hiramatsu /* Synthesize only event probe point */ 21224235b045SMasami Hiramatsu place = synthesize_perf_probe_point(&pev->point); 2123146a1439SMasami Hiramatsu if (!place) 2124146a1439SMasami Hiramatsu return -EINVAL; 21254235b045SMasami Hiramatsu 21264235b045SMasami Hiramatsu ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); 21277e990a51SMasami Hiramatsu if (ret < 0) 2128146a1439SMasami Hiramatsu return ret; 2129146a1439SMasami Hiramatsu 21305e17b28fSMasami Hiramatsu pr_info(" %-20s (on %s", buf, place); 2131fb226ccdSMasami Hiramatsu if (module) 21325e17b28fSMasami Hiramatsu pr_info(" in %s", module); 2133278498d4SMasami Hiramatsu 21344235b045SMasami Hiramatsu if (pev->nargs > 0) { 21355e17b28fSMasami Hiramatsu pr_info(" with"); 21367df2f329SMasami Hiramatsu for (i = 0; i < pev->nargs; i++) { 2137146a1439SMasami Hiramatsu ret = synthesize_perf_probe_arg(&pev->args[i], 2138146a1439SMasami Hiramatsu buf, 128); 2139146a1439SMasami Hiramatsu if (ret < 0) 2140146a1439SMasami Hiramatsu break; 21415e17b28fSMasami Hiramatsu pr_info(" %s", buf); 21427df2f329SMasami Hiramatsu } 2143278498d4SMasami Hiramatsu } 21445e17b28fSMasami Hiramatsu pr_info(")\n"); 21454235b045SMasami Hiramatsu free(place); 2146146a1439SMasami Hiramatsu return ret; 2147278498d4SMasami Hiramatsu } 2148278498d4SMasami Hiramatsu 2149225466f1SSrikar Dronamraju static int __show_perf_probe_events(int fd, bool is_kprobe) 21504de189feSMasami Hiramatsu { 2151225466f1SSrikar Dronamraju int ret = 0; 21520e60836bSSrikar Dronamraju struct probe_trace_event tev; 21534235b045SMasami Hiramatsu struct perf_probe_event pev; 21544de189feSMasami Hiramatsu struct strlist *rawlist; 21554de189feSMasami Hiramatsu struct str_node *ent; 21564de189feSMasami Hiramatsu 21574235b045SMasami Hiramatsu memset(&tev, 0, sizeof(tev)); 21584235b045SMasami Hiramatsu memset(&pev, 0, sizeof(pev)); 215972041334SMasami Hiramatsu 21600e60836bSSrikar Dronamraju rawlist = get_probe_trace_command_rawlist(fd); 2161146a1439SMasami Hiramatsu if (!rawlist) 21626eb08660SMasami Hiramatsu return -ENOMEM; 21634de189feSMasami Hiramatsu 2164adf365f4SMasami Hiramatsu strlist__for_each(ent, rawlist) { 21650e60836bSSrikar Dronamraju ret = parse_probe_trace_command(ent->s, &tev); 2166146a1439SMasami Hiramatsu if (ret >= 0) { 2167225466f1SSrikar Dronamraju ret = convert_to_perf_probe_event(&tev, &pev, 2168225466f1SSrikar Dronamraju is_kprobe); 2169146a1439SMasami Hiramatsu if (ret >= 0) 2170fb226ccdSMasami Hiramatsu ret = show_perf_probe_event(&pev, 2171fb226ccdSMasami Hiramatsu tev.point.module); 2172146a1439SMasami Hiramatsu } 21734235b045SMasami Hiramatsu clear_perf_probe_event(&pev); 21740e60836bSSrikar Dronamraju clear_probe_trace_event(&tev); 2175146a1439SMasami Hiramatsu if (ret < 0) 2176146a1439SMasami Hiramatsu break; 21774de189feSMasami Hiramatsu } 21784de189feSMasami Hiramatsu strlist__delete(rawlist); 2179146a1439SMasami Hiramatsu 2180146a1439SMasami Hiramatsu return ret; 21814de189feSMasami Hiramatsu } 21824de189feSMasami Hiramatsu 2183225466f1SSrikar Dronamraju /* List up current perf-probe events */ 2184225466f1SSrikar Dronamraju int show_perf_probe_events(void) 2185225466f1SSrikar Dronamraju { 21865e45187cSMasami Hiramatsu int kp_fd, up_fd, ret; 2187225466f1SSrikar Dronamraju 2188225466f1SSrikar Dronamraju setup_pager(); 2189225466f1SSrikar Dronamraju 2190ee45b6c2SMasami Hiramatsu ret = init_symbol_maps(false); 2191225466f1SSrikar Dronamraju if (ret < 0) 2192225466f1SSrikar Dronamraju return ret; 2193225466f1SSrikar Dronamraju 21945e45187cSMasami Hiramatsu kp_fd = open_kprobe_events(false); 21955e45187cSMasami Hiramatsu if (kp_fd >= 0) { 21965e45187cSMasami Hiramatsu ret = __show_perf_probe_events(kp_fd, true); 21975e45187cSMasami Hiramatsu close(kp_fd); 21985e45187cSMasami Hiramatsu if (ret < 0) 21995e45187cSMasami Hiramatsu goto out; 2200225466f1SSrikar Dronamraju } 2201225466f1SSrikar Dronamraju 22025e45187cSMasami Hiramatsu up_fd = open_uprobe_events(false); 22035e45187cSMasami Hiramatsu if (kp_fd < 0 && up_fd < 0) { 2204467ec085SMasami Hiramatsu print_both_open_warning(kp_fd, up_fd); 22055e45187cSMasami Hiramatsu ret = kp_fd; 22065e45187cSMasami Hiramatsu goto out; 22075e45187cSMasami Hiramatsu } 22085e45187cSMasami Hiramatsu 22095e45187cSMasami Hiramatsu if (up_fd >= 0) { 22105e45187cSMasami Hiramatsu ret = __show_perf_probe_events(up_fd, false); 22115e45187cSMasami Hiramatsu close(up_fd); 22125e45187cSMasami Hiramatsu } 22135e45187cSMasami Hiramatsu out: 2214ee45b6c2SMasami Hiramatsu exit_symbol_maps(); 2215225466f1SSrikar Dronamraju return ret; 2216225466f1SSrikar Dronamraju } 2217225466f1SSrikar Dronamraju 2218b498ce1fSMasami Hiramatsu /* Get current perf-probe event names */ 22190e60836bSSrikar Dronamraju static struct strlist *get_probe_trace_event_names(int fd, bool include_group) 2220b498ce1fSMasami Hiramatsu { 2221fa28244dSMasami Hiramatsu char buf[128]; 2222b498ce1fSMasami Hiramatsu struct strlist *sl, *rawlist; 2223b498ce1fSMasami Hiramatsu struct str_node *ent; 22240e60836bSSrikar Dronamraju struct probe_trace_event tev; 2225146a1439SMasami Hiramatsu int ret = 0; 2226b498ce1fSMasami Hiramatsu 22274235b045SMasami Hiramatsu memset(&tev, 0, sizeof(tev)); 22280e60836bSSrikar Dronamraju rawlist = get_probe_trace_command_rawlist(fd); 22296eb08660SMasami Hiramatsu if (!rawlist) 22306eb08660SMasami Hiramatsu return NULL; 2231e1d2017bSMasami Hiramatsu sl = strlist__new(true, NULL); 2232adf365f4SMasami Hiramatsu strlist__for_each(ent, rawlist) { 22330e60836bSSrikar Dronamraju ret = parse_probe_trace_command(ent->s, &tev); 2234146a1439SMasami Hiramatsu if (ret < 0) 2235146a1439SMasami Hiramatsu break; 2236fa28244dSMasami Hiramatsu if (include_group) { 2237146a1439SMasami Hiramatsu ret = e_snprintf(buf, 128, "%s:%s", tev.group, 2238146a1439SMasami Hiramatsu tev.event); 2239146a1439SMasami Hiramatsu if (ret >= 0) 2240146a1439SMasami Hiramatsu ret = strlist__add(sl, buf); 2241fa28244dSMasami Hiramatsu } else 2242146a1439SMasami Hiramatsu ret = strlist__add(sl, tev.event); 22430e60836bSSrikar Dronamraju clear_probe_trace_event(&tev); 2244146a1439SMasami Hiramatsu if (ret < 0) 2245146a1439SMasami Hiramatsu break; 2246b498ce1fSMasami Hiramatsu } 2247b498ce1fSMasami Hiramatsu strlist__delete(rawlist); 2248b498ce1fSMasami Hiramatsu 2249146a1439SMasami Hiramatsu if (ret < 0) { 2250146a1439SMasami Hiramatsu strlist__delete(sl); 2251146a1439SMasami Hiramatsu return NULL; 2252146a1439SMasami Hiramatsu } 2253b498ce1fSMasami Hiramatsu return sl; 2254b498ce1fSMasami Hiramatsu } 2255b498ce1fSMasami Hiramatsu 22560e60836bSSrikar Dronamraju static int write_probe_trace_event(int fd, struct probe_trace_event *tev) 225750656eecSMasami Hiramatsu { 22586eca8cc3SFrederic Weisbecker int ret = 0; 22590e60836bSSrikar Dronamraju char *buf = synthesize_probe_trace_command(tev); 22605f03cba4SMasami Hiramatsu char sbuf[STRERR_BUFSIZE]; 226150656eecSMasami Hiramatsu 2262146a1439SMasami Hiramatsu if (!buf) { 22630e60836bSSrikar Dronamraju pr_debug("Failed to synthesize probe trace event.\n"); 2264146a1439SMasami Hiramatsu return -EINVAL; 2265146a1439SMasami Hiramatsu } 2266146a1439SMasami Hiramatsu 2267fa28244dSMasami Hiramatsu pr_debug("Writing event: %s\n", buf); 2268f4d7da49SMasami Hiramatsu if (!probe_event_dry_run) { 226950656eecSMasami Hiramatsu ret = write(fd, buf, strlen(buf)); 22707949ba1fSNamhyung Kim if (ret <= 0) { 22717949ba1fSNamhyung Kim ret = -errno; 2272146a1439SMasami Hiramatsu pr_warning("Failed to write event: %s\n", 22735f03cba4SMasami Hiramatsu strerror_r(errno, sbuf, sizeof(sbuf))); 227450656eecSMasami Hiramatsu } 22757949ba1fSNamhyung Kim } 22764235b045SMasami Hiramatsu free(buf); 2277146a1439SMasami Hiramatsu return ret; 2278f4d7da49SMasami Hiramatsu } 227950656eecSMasami Hiramatsu 2280146a1439SMasami Hiramatsu static int get_new_event_name(char *buf, size_t len, const char *base, 2281d761b08bSMasami Hiramatsu struct strlist *namelist, bool allow_suffix) 2282b498ce1fSMasami Hiramatsu { 2283b498ce1fSMasami Hiramatsu int i, ret; 228417f88fcdSMasami Hiramatsu 228517f88fcdSMasami Hiramatsu /* Try no suffix */ 228617f88fcdSMasami Hiramatsu ret = e_snprintf(buf, len, "%s", base); 2287146a1439SMasami Hiramatsu if (ret < 0) { 22885f03cba4SMasami Hiramatsu pr_debug("snprintf() failed: %d\n", ret); 2289146a1439SMasami Hiramatsu return ret; 2290146a1439SMasami Hiramatsu } 229117f88fcdSMasami Hiramatsu if (!strlist__has_entry(namelist, buf)) 2292146a1439SMasami Hiramatsu return 0; 229317f88fcdSMasami Hiramatsu 2294d761b08bSMasami Hiramatsu if (!allow_suffix) { 2295d761b08bSMasami Hiramatsu pr_warning("Error: event \"%s\" already exists. " 2296d761b08bSMasami Hiramatsu "(Use -f to force duplicates.)\n", base); 2297146a1439SMasami Hiramatsu return -EEXIST; 2298d761b08bSMasami Hiramatsu } 2299d761b08bSMasami Hiramatsu 230017f88fcdSMasami Hiramatsu /* Try to add suffix */ 230117f88fcdSMasami Hiramatsu for (i = 1; i < MAX_EVENT_INDEX; i++) { 2302b498ce1fSMasami Hiramatsu ret = e_snprintf(buf, len, "%s_%d", base, i); 2303146a1439SMasami Hiramatsu if (ret < 0) { 23045f03cba4SMasami Hiramatsu pr_debug("snprintf() failed: %d\n", ret); 2305146a1439SMasami Hiramatsu return ret; 2306146a1439SMasami Hiramatsu } 2307b498ce1fSMasami Hiramatsu if (!strlist__has_entry(namelist, buf)) 2308b498ce1fSMasami Hiramatsu break; 2309b498ce1fSMasami Hiramatsu } 2310146a1439SMasami Hiramatsu if (i == MAX_EVENT_INDEX) { 2311146a1439SMasami Hiramatsu pr_warning("Too many events are on the same function.\n"); 2312146a1439SMasami Hiramatsu ret = -ERANGE; 2313b498ce1fSMasami Hiramatsu } 2314b498ce1fSMasami Hiramatsu 2315146a1439SMasami Hiramatsu return ret; 2316146a1439SMasami Hiramatsu } 2317146a1439SMasami Hiramatsu 231879702f61SMasami Hiramatsu /* Warn if the current kernel's uprobe implementation is old */ 231979702f61SMasami Hiramatsu static void warn_uprobe_event_compat(struct probe_trace_event *tev) 232079702f61SMasami Hiramatsu { 232179702f61SMasami Hiramatsu int i; 232279702f61SMasami Hiramatsu char *buf = synthesize_probe_trace_command(tev); 232379702f61SMasami Hiramatsu 232479702f61SMasami Hiramatsu /* Old uprobe event doesn't support memory dereference */ 232579702f61SMasami Hiramatsu if (!tev->uprobes || tev->nargs == 0 || !buf) 232679702f61SMasami Hiramatsu goto out; 232779702f61SMasami Hiramatsu 232879702f61SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) 232979702f61SMasami Hiramatsu if (strglobmatch(tev->args[i].value, "[$@+-]*")) { 233079702f61SMasami Hiramatsu pr_warning("Please upgrade your kernel to at least " 233179702f61SMasami Hiramatsu "3.14 to have access to feature %s\n", 233279702f61SMasami Hiramatsu tev->args[i].value); 233379702f61SMasami Hiramatsu break; 233479702f61SMasami Hiramatsu } 233579702f61SMasami Hiramatsu out: 233679702f61SMasami Hiramatsu free(buf); 233779702f61SMasami Hiramatsu } 233879702f61SMasami Hiramatsu 23390e60836bSSrikar Dronamraju static int __add_probe_trace_events(struct perf_probe_event *pev, 23400e60836bSSrikar Dronamraju struct probe_trace_event *tevs, 23414235b045SMasami Hiramatsu int ntevs, bool allow_suffix) 234250656eecSMasami Hiramatsu { 2343146a1439SMasami Hiramatsu int i, fd, ret; 23440e60836bSSrikar Dronamraju struct probe_trace_event *tev = NULL; 23454235b045SMasami Hiramatsu char buf[64]; 23464235b045SMasami Hiramatsu const char *event, *group; 2347b498ce1fSMasami Hiramatsu struct strlist *namelist; 23489aaf5a5fSMasami Hiramatsu LIST_HEAD(blacklist); 23499aaf5a5fSMasami Hiramatsu struct kprobe_blacklist_node *node; 235050656eecSMasami Hiramatsu 2351225466f1SSrikar Dronamraju if (pev->uprobes) 2352225466f1SSrikar Dronamraju fd = open_uprobe_events(true); 2353225466f1SSrikar Dronamraju else 2354f4d7da49SMasami Hiramatsu fd = open_kprobe_events(true); 2355225466f1SSrikar Dronamraju 23565e45187cSMasami Hiramatsu if (fd < 0) { 23575e45187cSMasami Hiramatsu print_open_warning(fd, !pev->uprobes); 2358146a1439SMasami Hiramatsu return fd; 23595e45187cSMasami Hiramatsu } 23605e45187cSMasami Hiramatsu 2361b498ce1fSMasami Hiramatsu /* Get current event names */ 23620e60836bSSrikar Dronamraju namelist = get_probe_trace_event_names(fd, false); 2363146a1439SMasami Hiramatsu if (!namelist) { 2364146a1439SMasami Hiramatsu pr_debug("Failed to get current event list.\n"); 2365146a1439SMasami Hiramatsu return -EIO; 2366146a1439SMasami Hiramatsu } 23679aaf5a5fSMasami Hiramatsu /* Get kprobe blacklist if exists */ 23689aaf5a5fSMasami Hiramatsu if (!pev->uprobes) { 23699aaf5a5fSMasami Hiramatsu ret = kprobe_blacklist__load(&blacklist); 23709aaf5a5fSMasami Hiramatsu if (ret < 0) 23719aaf5a5fSMasami Hiramatsu pr_debug("No kprobe blacklist support, ignored\n"); 23729aaf5a5fSMasami Hiramatsu } 237350656eecSMasami Hiramatsu 2374146a1439SMasami Hiramatsu ret = 0; 23755e17b28fSMasami Hiramatsu pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":"); 237602b95dadSMasami Hiramatsu for (i = 0; i < ntevs; i++) { 23774235b045SMasami Hiramatsu tev = &tevs[i]; 23789aaf5a5fSMasami Hiramatsu /* Ensure that the address is NOT blacklisted */ 23799aaf5a5fSMasami Hiramatsu node = kprobe_blacklist__find_by_address(&blacklist, 23809aaf5a5fSMasami Hiramatsu tev->point.address); 23819aaf5a5fSMasami Hiramatsu if (node) { 23829aaf5a5fSMasami Hiramatsu pr_warning("Warning: Skipped probing on blacklisted function: %s\n", node->symbol); 23839aaf5a5fSMasami Hiramatsu continue; 23849aaf5a5fSMasami Hiramatsu } 23859aaf5a5fSMasami Hiramatsu 23864235b045SMasami Hiramatsu if (pev->event) 23874235b045SMasami Hiramatsu event = pev->event; 23884235b045SMasami Hiramatsu else 23894235b045SMasami Hiramatsu if (pev->point.function) 23904235b045SMasami Hiramatsu event = pev->point.function; 23914235b045SMasami Hiramatsu else 23924235b045SMasami Hiramatsu event = tev->point.symbol; 23934235b045SMasami Hiramatsu if (pev->group) 23944235b045SMasami Hiramatsu group = pev->group; 23954235b045SMasami Hiramatsu else 23964235b045SMasami Hiramatsu group = PERFPROBE_GROUP; 23974235b045SMasami Hiramatsu 2398b498ce1fSMasami Hiramatsu /* Get an unused new event name */ 2399146a1439SMasami Hiramatsu ret = get_new_event_name(buf, 64, event, 2400146a1439SMasami Hiramatsu namelist, allow_suffix); 2401146a1439SMasami Hiramatsu if (ret < 0) 2402146a1439SMasami Hiramatsu break; 24034235b045SMasami Hiramatsu event = buf; 24044235b045SMasami Hiramatsu 240502b95dadSMasami Hiramatsu tev->event = strdup(event); 240602b95dadSMasami Hiramatsu tev->group = strdup(group); 240702b95dadSMasami Hiramatsu if (tev->event == NULL || tev->group == NULL) { 240802b95dadSMasami Hiramatsu ret = -ENOMEM; 240902b95dadSMasami Hiramatsu break; 241002b95dadSMasami Hiramatsu } 24110e60836bSSrikar Dronamraju ret = write_probe_trace_event(fd, tev); 2412146a1439SMasami Hiramatsu if (ret < 0) 2413146a1439SMasami Hiramatsu break; 2414b498ce1fSMasami Hiramatsu /* Add added event name to namelist */ 2415b498ce1fSMasami Hiramatsu strlist__add(namelist, event); 24164235b045SMasami Hiramatsu 24174235b045SMasami Hiramatsu /* Trick here - save current event/group */ 24184235b045SMasami Hiramatsu event = pev->event; 24194235b045SMasami Hiramatsu group = pev->group; 24204235b045SMasami Hiramatsu pev->event = tev->event; 24214235b045SMasami Hiramatsu pev->group = tev->group; 2422fb226ccdSMasami Hiramatsu show_perf_probe_event(pev, tev->point.module); 24234235b045SMasami Hiramatsu /* Trick here - restore current event/group */ 24244235b045SMasami Hiramatsu pev->event = (char *)event; 24254235b045SMasami Hiramatsu pev->group = (char *)group; 24264235b045SMasami Hiramatsu 2427d761b08bSMasami Hiramatsu /* 2428d761b08bSMasami Hiramatsu * Probes after the first probe which comes from same 2429d761b08bSMasami Hiramatsu * user input are always allowed to add suffix, because 2430d761b08bSMasami Hiramatsu * there might be several addresses corresponding to 2431d761b08bSMasami Hiramatsu * one code line. 2432d761b08bSMasami Hiramatsu */ 2433d761b08bSMasami Hiramatsu allow_suffix = true; 243450656eecSMasami Hiramatsu } 243579702f61SMasami Hiramatsu if (ret == -EINVAL && pev->uprobes) 243679702f61SMasami Hiramatsu warn_uprobe_event_compat(tev); 2437146a1439SMasami Hiramatsu 24389aaf5a5fSMasami Hiramatsu /* Note that it is possible to skip all events because of blacklist */ 24399aaf5a5fSMasami Hiramatsu if (ret >= 0 && tev->event) { 2440a9b495b0SMasami Hiramatsu /* Show how to use the event. */ 24415e17b28fSMasami Hiramatsu pr_info("\nYou can now use it in all perf tools, such as:\n\n"); 24425e17b28fSMasami Hiramatsu pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group, 2443146a1439SMasami Hiramatsu tev->event); 2444146a1439SMasami Hiramatsu } 2445a9b495b0SMasami Hiramatsu 24469aaf5a5fSMasami Hiramatsu kprobe_blacklist__delete(&blacklist); 2447e1d2017bSMasami Hiramatsu strlist__delete(namelist); 244850656eecSMasami Hiramatsu close(fd); 2449146a1439SMasami Hiramatsu return ret; 245050656eecSMasami Hiramatsu } 2451fa28244dSMasami Hiramatsu 2452564c62a4SNamhyung Kim static int find_probe_functions(struct map *map, char *name) 2453eb948e50SMasami Hiramatsu { 2454564c62a4SNamhyung Kim int found = 0; 24550a3873a8SArnaldo Carvalho de Melo struct symbol *sym; 2456564c62a4SNamhyung Kim 24570a3873a8SArnaldo Carvalho de Melo map__for_each_symbol_by_name(map, name, sym) { 2458564c62a4SNamhyung Kim if (sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) 2459564c62a4SNamhyung Kim found++; 2460eb948e50SMasami Hiramatsu } 2461564c62a4SNamhyung Kim 2462564c62a4SNamhyung Kim return found; 2463eb948e50SMasami Hiramatsu } 2464eb948e50SMasami Hiramatsu 2465eb948e50SMasami Hiramatsu #define strdup_or_goto(str, label) \ 2466eb948e50SMasami Hiramatsu ({ char *__p = strdup(str); if (!__p) goto label; __p; }) 2467eb948e50SMasami Hiramatsu 2468eb948e50SMasami Hiramatsu /* 2469eb948e50SMasami Hiramatsu * Find probe function addresses from map. 2470eb948e50SMasami Hiramatsu * Return an error or the number of found probe_trace_event 2471eb948e50SMasami Hiramatsu */ 2472eb948e50SMasami Hiramatsu static int find_probe_trace_events_from_map(struct perf_probe_event *pev, 2473eb948e50SMasami Hiramatsu struct probe_trace_event **tevs, 2474eb948e50SMasami Hiramatsu int max_tevs, const char *target) 2475eb948e50SMasami Hiramatsu { 2476eb948e50SMasami Hiramatsu struct map *map = NULL; 2477eb948e50SMasami Hiramatsu struct kmap *kmap = NULL; 2478eb948e50SMasami Hiramatsu struct ref_reloc_sym *reloc_sym = NULL; 2479eb948e50SMasami Hiramatsu struct symbol *sym; 2480eb948e50SMasami Hiramatsu struct probe_trace_event *tev; 2481eb948e50SMasami Hiramatsu struct perf_probe_point *pp = &pev->point; 2482eb948e50SMasami Hiramatsu struct probe_trace_point *tp; 2483564c62a4SNamhyung Kim int num_matched_functions; 2484eb948e50SMasami Hiramatsu int ret, i; 2485eb948e50SMasami Hiramatsu 2486*9b118acaSMasami Hiramatsu map = get_target_map(target, pev->uprobes); 2487eb948e50SMasami Hiramatsu if (!map) { 2488eb948e50SMasami Hiramatsu ret = -EINVAL; 2489eb948e50SMasami Hiramatsu goto out; 2490eb948e50SMasami Hiramatsu } 2491eb948e50SMasami Hiramatsu 2492eb948e50SMasami Hiramatsu /* 2493eb948e50SMasami Hiramatsu * Load matched symbols: Since the different local symbols may have 2494eb948e50SMasami Hiramatsu * same name but different addresses, this lists all the symbols. 2495eb948e50SMasami Hiramatsu */ 2496564c62a4SNamhyung Kim num_matched_functions = find_probe_functions(map, pp->function); 2497564c62a4SNamhyung Kim if (num_matched_functions == 0) { 2498eb948e50SMasami Hiramatsu pr_err("Failed to find symbol %s in %s\n", pp->function, 2499eb948e50SMasami Hiramatsu target ? : "kernel"); 2500eb948e50SMasami Hiramatsu ret = -ENOENT; 2501eb948e50SMasami Hiramatsu goto out; 2502eb948e50SMasami Hiramatsu } else if (num_matched_functions > max_tevs) { 2503eb948e50SMasami Hiramatsu pr_err("Too many functions matched in %s\n", 2504eb948e50SMasami Hiramatsu target ? : "kernel"); 2505eb948e50SMasami Hiramatsu ret = -E2BIG; 2506eb948e50SMasami Hiramatsu goto out; 2507eb948e50SMasami Hiramatsu } 2508eb948e50SMasami Hiramatsu 250925dd9171SNamhyung Kim if (!pev->uprobes && !pp->retprobe) { 2510eb948e50SMasami Hiramatsu kmap = map__kmap(map); 2511eb948e50SMasami Hiramatsu reloc_sym = kmap->ref_reloc_sym; 2512eb948e50SMasami Hiramatsu if (!reloc_sym) { 2513eb948e50SMasami Hiramatsu pr_warning("Relocated base symbol is not found!\n"); 2514eb948e50SMasami Hiramatsu ret = -EINVAL; 2515eb948e50SMasami Hiramatsu goto out; 2516eb948e50SMasami Hiramatsu } 2517eb948e50SMasami Hiramatsu } 2518eb948e50SMasami Hiramatsu 2519eb948e50SMasami Hiramatsu /* Setup result trace-probe-events */ 2520eb948e50SMasami Hiramatsu *tevs = zalloc(sizeof(*tev) * num_matched_functions); 2521eb948e50SMasami Hiramatsu if (!*tevs) { 2522eb948e50SMasami Hiramatsu ret = -ENOMEM; 2523eb948e50SMasami Hiramatsu goto out; 2524eb948e50SMasami Hiramatsu } 2525eb948e50SMasami Hiramatsu 2526eb948e50SMasami Hiramatsu ret = 0; 2527564c62a4SNamhyung Kim 25280a3873a8SArnaldo Carvalho de Melo map__for_each_symbol_by_name(map, pp->function, sym) { 2529eb948e50SMasami Hiramatsu tev = (*tevs) + ret; 2530eb948e50SMasami Hiramatsu tp = &tev->point; 2531eb948e50SMasami Hiramatsu if (ret == num_matched_functions) { 2532eb948e50SMasami Hiramatsu pr_warning("Too many symbols are listed. Skip it.\n"); 2533eb948e50SMasami Hiramatsu break; 2534eb948e50SMasami Hiramatsu } 2535eb948e50SMasami Hiramatsu ret++; 2536eb948e50SMasami Hiramatsu 2537eb948e50SMasami Hiramatsu if (pp->offset > sym->end - sym->start) { 2538eb948e50SMasami Hiramatsu pr_warning("Offset %ld is bigger than the size of %s\n", 2539eb948e50SMasami Hiramatsu pp->offset, sym->name); 2540eb948e50SMasami Hiramatsu ret = -ENOENT; 2541eb948e50SMasami Hiramatsu goto err_out; 2542eb948e50SMasami Hiramatsu } 2543eb948e50SMasami Hiramatsu /* Add one probe point */ 2544eb948e50SMasami Hiramatsu tp->address = map->unmap_ip(map, sym->start) + pp->offset; 2545eb948e50SMasami Hiramatsu if (reloc_sym) { 2546eb948e50SMasami Hiramatsu tp->symbol = strdup_or_goto(reloc_sym->name, nomem_out); 2547eb948e50SMasami Hiramatsu tp->offset = tp->address - reloc_sym->addr; 2548eb948e50SMasami Hiramatsu } else { 2549eb948e50SMasami Hiramatsu tp->symbol = strdup_or_goto(sym->name, nomem_out); 2550eb948e50SMasami Hiramatsu tp->offset = pp->offset; 2551eb948e50SMasami Hiramatsu } 2552eb948e50SMasami Hiramatsu tp->retprobe = pp->retprobe; 2553eb948e50SMasami Hiramatsu if (target) 2554eb948e50SMasami Hiramatsu tev->point.module = strdup_or_goto(target, nomem_out); 2555eb948e50SMasami Hiramatsu tev->uprobes = pev->uprobes; 2556eb948e50SMasami Hiramatsu tev->nargs = pev->nargs; 2557eb948e50SMasami Hiramatsu if (tev->nargs) { 2558eb948e50SMasami Hiramatsu tev->args = zalloc(sizeof(struct probe_trace_arg) * 2559eb948e50SMasami Hiramatsu tev->nargs); 2560eb948e50SMasami Hiramatsu if (tev->args == NULL) 2561eb948e50SMasami Hiramatsu goto nomem_out; 2562eb948e50SMasami Hiramatsu } 2563eb948e50SMasami Hiramatsu for (i = 0; i < tev->nargs; i++) { 2564eb948e50SMasami Hiramatsu if (pev->args[i].name) 2565eb948e50SMasami Hiramatsu tev->args[i].name = 2566eb948e50SMasami Hiramatsu strdup_or_goto(pev->args[i].name, 2567eb948e50SMasami Hiramatsu nomem_out); 2568eb948e50SMasami Hiramatsu 2569eb948e50SMasami Hiramatsu tev->args[i].value = strdup_or_goto(pev->args[i].var, 2570eb948e50SMasami Hiramatsu nomem_out); 2571eb948e50SMasami Hiramatsu if (pev->args[i].type) 2572eb948e50SMasami Hiramatsu tev->args[i].type = 2573eb948e50SMasami Hiramatsu strdup_or_goto(pev->args[i].type, 2574eb948e50SMasami Hiramatsu nomem_out); 2575eb948e50SMasami Hiramatsu } 2576eb948e50SMasami Hiramatsu } 2577eb948e50SMasami Hiramatsu 2578eb948e50SMasami Hiramatsu out: 2579*9b118acaSMasami Hiramatsu put_target_map(map, pev->uprobes); 2580eb948e50SMasami Hiramatsu return ret; 2581eb948e50SMasami Hiramatsu 2582eb948e50SMasami Hiramatsu nomem_out: 2583eb948e50SMasami Hiramatsu ret = -ENOMEM; 2584eb948e50SMasami Hiramatsu err_out: 2585eb948e50SMasami Hiramatsu clear_probe_trace_events(*tevs, num_matched_functions); 2586eb948e50SMasami Hiramatsu zfree(tevs); 2587eb948e50SMasami Hiramatsu goto out; 2588eb948e50SMasami Hiramatsu } 2589eb948e50SMasami Hiramatsu 25900e60836bSSrikar Dronamraju static int convert_to_probe_trace_events(struct perf_probe_event *pev, 25910e60836bSSrikar Dronamraju struct probe_trace_event **tevs, 25924eced234SSrikar Dronamraju int max_tevs, const char *target) 2593e0faa8d3SMasami Hiramatsu { 2594eb948e50SMasami Hiramatsu int ret; 25954235b045SMasami Hiramatsu 2596fb7345bbSMasami Hiramatsu if (pev->uprobes && !pev->group) { 2597fb7345bbSMasami Hiramatsu /* Replace group name if not given */ 2598fb7345bbSMasami Hiramatsu ret = convert_exec_to_group(target, &pev->group); 2599fb7345bbSMasami Hiramatsu if (ret != 0) { 2600fb7345bbSMasami Hiramatsu pr_warning("Failed to make a group name.\n"); 2601fb7345bbSMasami Hiramatsu return ret; 2602fb7345bbSMasami Hiramatsu } 2603fb7345bbSMasami Hiramatsu } 2604fb7345bbSMasami Hiramatsu 26054b4da7f7SMasami Hiramatsu /* Convert perf_probe_event with debuginfo */ 26064eced234SSrikar Dronamraju ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, target); 2607e334016fSMasami Hiramatsu if (ret != 0) 2608190b57fcSMasami Hiramatsu return ret; /* Found in debuginfo or got an error */ 2609e0faa8d3SMasami Hiramatsu 2610eb948e50SMasami Hiramatsu return find_probe_trace_events_from_map(pev, tevs, max_tevs, target); 26114235b045SMasami Hiramatsu } 26124235b045SMasami Hiramatsu 26134235b045SMasami Hiramatsu struct __event_package { 26144235b045SMasami Hiramatsu struct perf_probe_event *pev; 26150e60836bSSrikar Dronamraju struct probe_trace_event *tevs; 26164235b045SMasami Hiramatsu int ntevs; 26174235b045SMasami Hiramatsu }; 26184235b045SMasami Hiramatsu 2619146a1439SMasami Hiramatsu int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, 26204eced234SSrikar Dronamraju int max_tevs, const char *target, bool force_add) 26214235b045SMasami Hiramatsu { 2622146a1439SMasami Hiramatsu int i, j, ret; 26234235b045SMasami Hiramatsu struct __event_package *pkgs; 26244235b045SMasami Hiramatsu 2625225466f1SSrikar Dronamraju ret = 0; 2626e334016fSMasami Hiramatsu pkgs = zalloc(sizeof(struct __event_package) * npevs); 2627225466f1SSrikar Dronamraju 2628e334016fSMasami Hiramatsu if (pkgs == NULL) 2629e334016fSMasami Hiramatsu return -ENOMEM; 26304235b045SMasami Hiramatsu 2631ee45b6c2SMasami Hiramatsu ret = init_symbol_maps(pevs->uprobes); 2632449e5b24SMasami Hiramatsu if (ret < 0) { 2633449e5b24SMasami Hiramatsu free(pkgs); 2634146a1439SMasami Hiramatsu return ret; 2635449e5b24SMasami Hiramatsu } 26364235b045SMasami Hiramatsu 26374235b045SMasami Hiramatsu /* Loop 1: convert all events */ 26384235b045SMasami Hiramatsu for (i = 0; i < npevs; i++) { 26394235b045SMasami Hiramatsu pkgs[i].pev = &pevs[i]; 26404235b045SMasami Hiramatsu /* Convert with or without debuginfo */ 26410e60836bSSrikar Dronamraju ret = convert_to_probe_trace_events(pkgs[i].pev, 2642469b9b88SMasami Hiramatsu &pkgs[i].tevs, 2643469b9b88SMasami Hiramatsu max_tevs, 26444eced234SSrikar Dronamraju target); 2645146a1439SMasami Hiramatsu if (ret < 0) 2646146a1439SMasami Hiramatsu goto end; 2647146a1439SMasami Hiramatsu pkgs[i].ntevs = ret; 26484235b045SMasami Hiramatsu } 26494235b045SMasami Hiramatsu 26504235b045SMasami Hiramatsu /* Loop 2: add all events */ 26518635bf6eSArnaldo Carvalho de Melo for (i = 0; i < npevs; i++) { 26520e60836bSSrikar Dronamraju ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, 26534235b045SMasami Hiramatsu pkgs[i].ntevs, force_add); 2654fbee632dSArnaldo Carvalho de Melo if (ret < 0) 2655fbee632dSArnaldo Carvalho de Melo break; 2656fbee632dSArnaldo Carvalho de Melo } 2657146a1439SMasami Hiramatsu end: 2658449e5b24SMasami Hiramatsu /* Loop 3: cleanup and free trace events */ 2659449e5b24SMasami Hiramatsu for (i = 0; i < npevs; i++) { 2660146a1439SMasami Hiramatsu for (j = 0; j < pkgs[i].ntevs; j++) 26610e60836bSSrikar Dronamraju clear_probe_trace_event(&pkgs[i].tevs[j]); 266274cf249dSArnaldo Carvalho de Melo zfree(&pkgs[i].tevs); 2663449e5b24SMasami Hiramatsu } 2664449e5b24SMasami Hiramatsu free(pkgs); 2665ee45b6c2SMasami Hiramatsu exit_symbol_maps(); 2666146a1439SMasami Hiramatsu 2667146a1439SMasami Hiramatsu return ret; 2668e0faa8d3SMasami Hiramatsu } 2669e0faa8d3SMasami Hiramatsu 26700e60836bSSrikar Dronamraju static int __del_trace_probe_event(int fd, struct str_node *ent) 2671bbbb521bSMasami Hiramatsu { 2672bbbb521bSMasami Hiramatsu char *p; 2673bbbb521bSMasami Hiramatsu char buf[128]; 26744235b045SMasami Hiramatsu int ret; 2675bbbb521bSMasami Hiramatsu 26760e60836bSSrikar Dronamraju /* Convert from perf-probe event to trace-probe event */ 2677146a1439SMasami Hiramatsu ret = e_snprintf(buf, 128, "-:%s", ent->s); 2678146a1439SMasami Hiramatsu if (ret < 0) 2679146a1439SMasami Hiramatsu goto error; 2680146a1439SMasami Hiramatsu 2681bbbb521bSMasami Hiramatsu p = strchr(buf + 2, ':'); 2682146a1439SMasami Hiramatsu if (!p) { 2683146a1439SMasami Hiramatsu pr_debug("Internal error: %s should have ':' but not.\n", 2684146a1439SMasami Hiramatsu ent->s); 2685146a1439SMasami Hiramatsu ret = -ENOTSUP; 2686146a1439SMasami Hiramatsu goto error; 2687146a1439SMasami Hiramatsu } 2688bbbb521bSMasami Hiramatsu *p = '/'; 2689bbbb521bSMasami Hiramatsu 26904235b045SMasami Hiramatsu pr_debug("Writing event: %s\n", buf); 26914235b045SMasami Hiramatsu ret = write(fd, buf, strlen(buf)); 269244a56040SMasami Hiramatsu if (ret < 0) { 269344a56040SMasami Hiramatsu ret = -errno; 2694146a1439SMasami Hiramatsu goto error; 269544a56040SMasami Hiramatsu } 2696146a1439SMasami Hiramatsu 26975e17b28fSMasami Hiramatsu pr_info("Removed event: %s\n", ent->s); 2698146a1439SMasami Hiramatsu return 0; 2699146a1439SMasami Hiramatsu error: 27005f03cba4SMasami Hiramatsu pr_warning("Failed to delete event: %s\n", 27015f03cba4SMasami Hiramatsu strerror_r(-ret, buf, sizeof(buf))); 2702146a1439SMasami Hiramatsu return ret; 2703bbbb521bSMasami Hiramatsu } 2704bbbb521bSMasami Hiramatsu 2705225466f1SSrikar Dronamraju static int del_trace_probe_event(int fd, const char *buf, 2706225466f1SSrikar Dronamraju struct strlist *namelist) 2707fa28244dSMasami Hiramatsu { 2708bbbb521bSMasami Hiramatsu struct str_node *ent, *n; 2709225466f1SSrikar Dronamraju int ret = -1; 2710fa28244dSMasami Hiramatsu 2711bbbb521bSMasami Hiramatsu if (strpbrk(buf, "*?")) { /* Glob-exp */ 2712bbbb521bSMasami Hiramatsu strlist__for_each_safe(ent, n, namelist) 2713bbbb521bSMasami Hiramatsu if (strglobmatch(ent->s, buf)) { 27140e60836bSSrikar Dronamraju ret = __del_trace_probe_event(fd, ent); 2715146a1439SMasami Hiramatsu if (ret < 0) 2716146a1439SMasami Hiramatsu break; 27173e340590SMasami Hiramatsu strlist__remove(namelist, ent); 2718fa28244dSMasami Hiramatsu } 2719bbbb521bSMasami Hiramatsu } else { 2720bbbb521bSMasami Hiramatsu ent = strlist__find(namelist, buf); 2721bbbb521bSMasami Hiramatsu if (ent) { 27220e60836bSSrikar Dronamraju ret = __del_trace_probe_event(fd, ent); 2723146a1439SMasami Hiramatsu if (ret >= 0) 2724bbbb521bSMasami Hiramatsu strlist__remove(namelist, ent); 2725bbbb521bSMasami Hiramatsu } 2726bbbb521bSMasami Hiramatsu } 2727146a1439SMasami Hiramatsu 2728146a1439SMasami Hiramatsu return ret; 2729bbbb521bSMasami Hiramatsu } 2730fa28244dSMasami Hiramatsu 2731146a1439SMasami Hiramatsu int del_perf_probe_events(struct strlist *dellist) 2732fa28244dSMasami Hiramatsu { 2733225466f1SSrikar Dronamraju int ret = -1, ufd = -1, kfd = -1; 2734225466f1SSrikar Dronamraju char buf[128]; 2735fa28244dSMasami Hiramatsu const char *group, *event; 2736fa28244dSMasami Hiramatsu char *p, *str; 2737fa28244dSMasami Hiramatsu struct str_node *ent; 2738225466f1SSrikar Dronamraju struct strlist *namelist = NULL, *unamelist = NULL; 2739146a1439SMasami Hiramatsu 2740fa28244dSMasami Hiramatsu /* Get current event names */ 2741225466f1SSrikar Dronamraju kfd = open_kprobe_events(true); 2742467ec085SMasami Hiramatsu if (kfd >= 0) 2743225466f1SSrikar Dronamraju namelist = get_probe_trace_event_names(kfd, true); 2744225466f1SSrikar Dronamraju 2745467ec085SMasami Hiramatsu ufd = open_uprobe_events(true); 2746467ec085SMasami Hiramatsu if (ufd >= 0) 2747225466f1SSrikar Dronamraju unamelist = get_probe_trace_event_names(ufd, true); 2748225466f1SSrikar Dronamraju 2749467ec085SMasami Hiramatsu if (kfd < 0 && ufd < 0) { 2750467ec085SMasami Hiramatsu print_both_open_warning(kfd, ufd); 2751467ec085SMasami Hiramatsu goto error; 2752467ec085SMasami Hiramatsu } 2753467ec085SMasami Hiramatsu 2754225466f1SSrikar Dronamraju if (namelist == NULL && unamelist == NULL) 2755225466f1SSrikar Dronamraju goto error; 2756fa28244dSMasami Hiramatsu 2757adf365f4SMasami Hiramatsu strlist__for_each(ent, dellist) { 275802b95dadSMasami Hiramatsu str = strdup(ent->s); 275902b95dadSMasami Hiramatsu if (str == NULL) { 276002b95dadSMasami Hiramatsu ret = -ENOMEM; 2761225466f1SSrikar Dronamraju goto error; 276202b95dadSMasami Hiramatsu } 2763bbbb521bSMasami Hiramatsu pr_debug("Parsing: %s\n", str); 2764fa28244dSMasami Hiramatsu p = strchr(str, ':'); 2765fa28244dSMasami Hiramatsu if (p) { 2766fa28244dSMasami Hiramatsu group = str; 2767fa28244dSMasami Hiramatsu *p = '\0'; 2768fa28244dSMasami Hiramatsu event = p + 1; 2769fa28244dSMasami Hiramatsu } else { 2770bbbb521bSMasami Hiramatsu group = "*"; 2771fa28244dSMasami Hiramatsu event = str; 2772fa28244dSMasami Hiramatsu } 2773225466f1SSrikar Dronamraju 2774225466f1SSrikar Dronamraju ret = e_snprintf(buf, 128, "%s:%s", group, event); 2775225466f1SSrikar Dronamraju if (ret < 0) { 2776225466f1SSrikar Dronamraju pr_err("Failed to copy event."); 2777fa28244dSMasami Hiramatsu free(str); 2778225466f1SSrikar Dronamraju goto error; 2779fa28244dSMasami Hiramatsu } 2780225466f1SSrikar Dronamraju 2781225466f1SSrikar Dronamraju pr_debug("Group: %s, Event: %s\n", group, event); 2782225466f1SSrikar Dronamraju 2783225466f1SSrikar Dronamraju if (namelist) 2784225466f1SSrikar Dronamraju ret = del_trace_probe_event(kfd, buf, namelist); 2785225466f1SSrikar Dronamraju 2786225466f1SSrikar Dronamraju if (unamelist && ret != 0) 2787225466f1SSrikar Dronamraju ret = del_trace_probe_event(ufd, buf, unamelist); 2788225466f1SSrikar Dronamraju 2789225466f1SSrikar Dronamraju if (ret != 0) 2790225466f1SSrikar Dronamraju pr_info("Info: Event \"%s\" does not exist.\n", buf); 2791225466f1SSrikar Dronamraju 2792225466f1SSrikar Dronamraju free(str); 2793225466f1SSrikar Dronamraju } 2794225466f1SSrikar Dronamraju 2795225466f1SSrikar Dronamraju error: 2796225466f1SSrikar Dronamraju if (kfd >= 0) { 2797fa28244dSMasami Hiramatsu strlist__delete(namelist); 2798225466f1SSrikar Dronamraju close(kfd); 2799225466f1SSrikar Dronamraju } 2800225466f1SSrikar Dronamraju 2801225466f1SSrikar Dronamraju if (ufd >= 0) { 2802225466f1SSrikar Dronamraju strlist__delete(unamelist); 2803225466f1SSrikar Dronamraju close(ufd); 2804225466f1SSrikar Dronamraju } 2805146a1439SMasami Hiramatsu 2806146a1439SMasami Hiramatsu return ret; 2807fa28244dSMasami Hiramatsu } 2808225466f1SSrikar Dronamraju 28093c42258cSMasami Hiramatsu /* TODO: don't use a global variable for filter ... */ 28103c42258cSMasami Hiramatsu static struct strfilter *available_func_filter; 2811fa28244dSMasami Hiramatsu 2812e80711caSMasami Hiramatsu /* 28133c42258cSMasami Hiramatsu * If a symbol corresponds to a function with global binding and 28143c42258cSMasami Hiramatsu * matches filter return 0. For all others return 1. 2815e80711caSMasami Hiramatsu */ 28161d037ca1SIrina Tirdea static int filter_available_functions(struct map *map __maybe_unused, 2817e80711caSMasami Hiramatsu struct symbol *sym) 2818e80711caSMasami Hiramatsu { 2819eb948e50SMasami Hiramatsu if ((sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) && 28203c42258cSMasami Hiramatsu strfilter__compare(available_func_filter, sym->name)) 2821e80711caSMasami Hiramatsu return 0; 28223c42258cSMasami Hiramatsu return 1; 2823e80711caSMasami Hiramatsu } 2824e80711caSMasami Hiramatsu 28252df58634SMasami Hiramatsu int show_available_funcs(const char *target, struct strfilter *_filter, 28262df58634SMasami Hiramatsu bool user) 2827e80711caSMasami Hiramatsu { 28282df58634SMasami Hiramatsu struct map *map; 28292df58634SMasami Hiramatsu int ret; 28302df58634SMasami Hiramatsu 28312df58634SMasami Hiramatsu ret = init_symbol_maps(user); 28322df58634SMasami Hiramatsu if (ret < 0) 28332df58634SMasami Hiramatsu return ret; 28342df58634SMasami Hiramatsu 28352df58634SMasami Hiramatsu /* Get a symbol map */ 28362df58634SMasami Hiramatsu if (user) 28372df58634SMasami Hiramatsu map = dso__new_map(target); 28382df58634SMasami Hiramatsu else 28392df58634SMasami Hiramatsu map = kernel_get_module_map(target); 28402df58634SMasami Hiramatsu if (!map) { 28412df58634SMasami Hiramatsu pr_err("Failed to get a map for %s\n", (target) ? : "kernel"); 2842e80711caSMasami Hiramatsu return -EINVAL; 2843e80711caSMasami Hiramatsu } 28442df58634SMasami Hiramatsu 28452df58634SMasami Hiramatsu /* Load symbols with given filter */ 28462df58634SMasami Hiramatsu available_func_filter = _filter; 28472df58634SMasami Hiramatsu if (map__load(map, filter_available_functions)) { 28482df58634SMasami Hiramatsu pr_err("Failed to load symbols in %s\n", (target) ? : "kernel"); 28492df58634SMasami Hiramatsu goto end; 28502df58634SMasami Hiramatsu } 2851e80711caSMasami Hiramatsu if (!dso__sorted_by_name(map->dso, map->type)) 2852e80711caSMasami Hiramatsu dso__sort_by_name(map->dso, map->type); 2853e80711caSMasami Hiramatsu 28542df58634SMasami Hiramatsu /* Show all (filtered) symbols */ 28552df58634SMasami Hiramatsu setup_pager(); 2856e80711caSMasami Hiramatsu dso__fprintf_symbols_by_name(map->dso, map->type, stdout); 28572df58634SMasami Hiramatsu end: 28582df58634SMasami Hiramatsu if (user) { 2859225466f1SSrikar Dronamraju dso__delete(map->dso); 2860225466f1SSrikar Dronamraju map__delete(map); 2861225466f1SSrikar Dronamraju } 28622df58634SMasami Hiramatsu exit_symbol_maps(); 2863225466f1SSrikar Dronamraju 28642df58634SMasami Hiramatsu return ret; 2865225466f1SSrikar Dronamraju } 2866225466f1SSrikar Dronamraju 2867