1 /* 2 * builtin-probe.c 3 * 4 * Builtin probe command: Set up probe events by C expression 5 * 6 * Written by Masami Hiramatsu <mhiramat@redhat.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 21 * 22 */ 23 #define _GNU_SOURCE 24 #include <sys/utsname.h> 25 #include <sys/types.h> 26 #include <sys/stat.h> 27 #include <fcntl.h> 28 #include <errno.h> 29 #include <stdio.h> 30 #include <unistd.h> 31 #include <stdlib.h> 32 #include <string.h> 33 34 #undef _GNU_SOURCE 35 #include "perf.h" 36 #include "builtin.h" 37 #include "util/util.h" 38 #include "util/strlist.h" 39 #include "util/event.h" 40 #include "util/debug.h" 41 #include "util/debugfs.h" 42 #include "util/symbol.h" 43 #include "util/thread.h" 44 #include "util/parse-options.h" 45 #include "util/parse-events.h" /* For debugfs_path */ 46 #include "util/probe-finder.h" 47 #include "util/probe-event.h" 48 49 #define MAX_PATH_LEN 256 50 51 /* Session management structure */ 52 static struct { 53 bool need_dwarf; 54 bool list_events; 55 bool force_add; 56 bool show_lines; 57 int nr_probe; 58 struct probe_point probes[MAX_PROBES]; 59 struct strlist *dellist; 60 struct map_groups kmap_groups; 61 struct map *kmaps[MAP__NR_TYPES]; 62 struct line_range line_range; 63 } session; 64 65 66 /* Parse an event definition. Note that any error must die. */ 67 static void parse_probe_event(const char *str) 68 { 69 struct probe_point *pp = &session.probes[session.nr_probe]; 70 71 pr_debug("probe-definition(%d): %s\n", session.nr_probe, str); 72 if (++session.nr_probe == MAX_PROBES) 73 die("Too many probes (> %d) are specified.", MAX_PROBES); 74 75 /* Parse perf-probe event into probe_point */ 76 parse_perf_probe_event(str, pp, &session.need_dwarf); 77 78 pr_debug("%d arguments\n", pp->nr_args); 79 } 80 81 static void parse_probe_event_argv(int argc, const char **argv) 82 { 83 int i, len; 84 char *buf; 85 86 /* Bind up rest arguments */ 87 len = 0; 88 for (i = 0; i < argc; i++) 89 len += strlen(argv[i]) + 1; 90 buf = zalloc(len + 1); 91 if (!buf) 92 die("Failed to allocate memory for binding arguments."); 93 len = 0; 94 for (i = 0; i < argc; i++) 95 len += sprintf(&buf[len], "%s ", argv[i]); 96 parse_probe_event(buf); 97 free(buf); 98 } 99 100 static int opt_add_probe_event(const struct option *opt __used, 101 const char *str, int unset __used) 102 { 103 if (str) 104 parse_probe_event(str); 105 return 0; 106 } 107 108 static int opt_del_probe_event(const struct option *opt __used, 109 const char *str, int unset __used) 110 { 111 if (str) { 112 if (!session.dellist) 113 session.dellist = strlist__new(true, NULL); 114 strlist__add(session.dellist, str); 115 } 116 return 0; 117 } 118 119 /* Currently just checking function name from symbol map */ 120 static void evaluate_probe_point(struct probe_point *pp) 121 { 122 struct symbol *sym; 123 sym = map__find_symbol_by_name(session.kmaps[MAP__FUNCTION], 124 pp->function, NULL); 125 if (!sym) 126 die("Kernel symbol \'%s\' not found - probe not added.", 127 pp->function); 128 } 129 130 #ifndef NO_DWARF_SUPPORT 131 static int open_vmlinux(void) 132 { 133 if (map__load(session.kmaps[MAP__FUNCTION], NULL) < 0) { 134 pr_debug("Failed to load kernel map.\n"); 135 return -EINVAL; 136 } 137 pr_debug("Try to open %s\n", 138 session.kmaps[MAP__FUNCTION]->dso->long_name); 139 return open(session.kmaps[MAP__FUNCTION]->dso->long_name, O_RDONLY); 140 } 141 142 static int opt_show_lines(const struct option *opt __used, 143 const char *str, int unset __used) 144 { 145 if (str) 146 parse_line_range_desc(str, &session.line_range); 147 INIT_LIST_HEAD(&session.line_range.line_list); 148 session.show_lines = true; 149 return 0; 150 } 151 #endif 152 153 static const char * const probe_usage[] = { 154 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", 155 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 156 "perf probe [<options>] --del '[GROUP:]EVENT' ...", 157 "perf probe --list", 158 #ifndef NO_DWARF_SUPPORT 159 "perf probe --line 'LINEDESC'", 160 #endif 161 NULL 162 }; 163 164 static const struct option options[] = { 165 OPT_BOOLEAN('v', "verbose", &verbose, 166 "be more verbose (show parsed arguments, etc)"), 167 #ifndef NO_DWARF_SUPPORT 168 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 169 "file", "vmlinux pathname"), 170 #endif 171 OPT_BOOLEAN('l', "list", &session.list_events, 172 "list up current probe events"), 173 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", 174 opt_del_probe_event), 175 OPT_CALLBACK('a', "add", NULL, 176 #ifdef NO_DWARF_SUPPORT 177 "[EVENT=]FUNC[+OFF|%return] [ARG ...]", 178 #else 179 "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" 180 " [ARG ...]", 181 #endif 182 "probe point definition, where\n" 183 "\t\tGROUP:\tGroup name (optional)\n" 184 "\t\tEVENT:\tEvent name\n" 185 "\t\tFUNC:\tFunction name\n" 186 "\t\tOFF:\tOffset from function entry (in byte)\n" 187 "\t\t%return:\tPut the probe at function return\n" 188 #ifdef NO_DWARF_SUPPORT 189 "\t\tARG:\tProbe argument (only \n" 190 #else 191 "\t\tSRC:\tSource code path\n" 192 "\t\tRL:\tRelative line number from function entry.\n" 193 "\t\tAL:\tAbsolute line number in file.\n" 194 "\t\tPT:\tLazy expression of line code.\n" 195 "\t\tARG:\tProbe argument (local variable name or\n" 196 #endif 197 "\t\t\tkprobe-tracer argument format.)\n", 198 opt_add_probe_event), 199 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events" 200 " with existing name"), 201 #ifndef NO_DWARF_SUPPORT 202 OPT_CALLBACK('L', "line", NULL, 203 "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]", 204 "Show source code lines.", opt_show_lines), 205 #endif 206 OPT_END() 207 }; 208 209 /* Initialize symbol maps for vmlinux */ 210 static void init_vmlinux(void) 211 { 212 symbol_conf.sort_by_name = true; 213 if (symbol_conf.vmlinux_name == NULL) 214 symbol_conf.try_vmlinux_path = true; 215 else 216 pr_debug("Use vmlinux: %s\n", symbol_conf.vmlinux_name); 217 if (symbol__init() < 0) 218 die("Failed to init symbol map."); 219 220 map_groups__init(&session.kmap_groups); 221 if (map_groups__create_kernel_maps(&session.kmap_groups, 222 session.kmaps) < 0) 223 die("Failed to create kernel maps."); 224 } 225 226 int cmd_probe(int argc, const char **argv, const char *prefix __used) 227 { 228 int i, ret; 229 #ifndef NO_DWARF_SUPPORT 230 int fd; 231 #endif 232 struct probe_point *pp; 233 234 argc = parse_options(argc, argv, options, probe_usage, 235 PARSE_OPT_STOP_AT_NON_OPTION); 236 if (argc > 0) { 237 if (strcmp(argv[0], "-") == 0) { 238 pr_warning(" Error: '-' is not supported.\n"); 239 usage_with_options(probe_usage, options); 240 } 241 parse_probe_event_argv(argc, argv); 242 } 243 244 if ((!session.nr_probe && !session.dellist && !session.list_events && 245 !session.show_lines)) 246 usage_with_options(probe_usage, options); 247 248 if (debugfs_valid_mountpoint(debugfs_path) < 0) 249 die("Failed to find debugfs path."); 250 251 if (session.list_events) { 252 if (session.nr_probe != 0 || session.dellist) { 253 pr_warning(" Error: Don't use --list with" 254 " --add/--del.\n"); 255 usage_with_options(probe_usage, options); 256 } 257 if (session.show_lines) { 258 pr_warning(" Error: Don't use --list with --line.\n"); 259 usage_with_options(probe_usage, options); 260 } 261 show_perf_probe_events(); 262 return 0; 263 } 264 265 #ifndef NO_DWARF_SUPPORT 266 if (session.show_lines) { 267 if (session.nr_probe != 0 || session.dellist) { 268 pr_warning(" Error: Don't use --line with" 269 " --add/--del.\n"); 270 usage_with_options(probe_usage, options); 271 } 272 init_vmlinux(); 273 fd = open_vmlinux(); 274 if (fd < 0) 275 die("Could not open debuginfo file."); 276 ret = find_line_range(fd, &session.line_range); 277 if (ret <= 0) 278 die("Source line is not found.\n"); 279 close(fd); 280 show_line_range(&session.line_range); 281 return 0; 282 } 283 #endif 284 285 if (session.dellist) { 286 del_trace_kprobe_events(session.dellist); 287 strlist__delete(session.dellist); 288 if (session.nr_probe == 0) 289 return 0; 290 } 291 292 /* Add probes */ 293 init_vmlinux(); 294 295 if (session.need_dwarf) 296 #ifdef NO_DWARF_SUPPORT 297 die("Debuginfo-analysis is not supported"); 298 #else /* !NO_DWARF_SUPPORT */ 299 pr_debug("Some probes require debuginfo.\n"); 300 301 fd = open_vmlinux(); 302 if (fd < 0) { 303 if (session.need_dwarf) 304 die("Could not open debuginfo file."); 305 306 pr_debug("Could not open vmlinux/module file." 307 " Try to use symbols.\n"); 308 goto end_dwarf; 309 } 310 311 /* Searching probe points */ 312 for (i = 0; i < session.nr_probe; i++) { 313 pp = &session.probes[i]; 314 if (pp->found) 315 continue; 316 317 lseek(fd, SEEK_SET, 0); 318 ret = find_probe_point(fd, pp); 319 if (ret > 0) 320 continue; 321 if (ret == 0) { /* No error but failed to find probe point. */ 322 synthesize_perf_probe_point(pp); 323 die("Probe point '%s' not found. - probe not added.", 324 pp->probes[0]); 325 } 326 /* Error path */ 327 if (session.need_dwarf) { 328 if (ret == -ENOENT) 329 pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n"); 330 die("Could not analyze debuginfo."); 331 } 332 pr_debug("An error occurred in debuginfo analysis." 333 " Try to use symbols.\n"); 334 break; 335 } 336 close(fd); 337 338 end_dwarf: 339 #endif /* !NO_DWARF_SUPPORT */ 340 341 /* Synthesize probes without dwarf */ 342 for (i = 0; i < session.nr_probe; i++) { 343 pp = &session.probes[i]; 344 if (pp->found) /* This probe is already found. */ 345 continue; 346 347 evaluate_probe_point(pp); 348 ret = synthesize_trace_kprobe_event(pp); 349 if (ret == -E2BIG) 350 die("probe point definition becomes too long."); 351 else if (ret < 0) 352 die("Failed to synthesize a probe point."); 353 } 354 355 /* Settng up probe points */ 356 add_trace_kprobe_events(session.probes, session.nr_probe, 357 session.force_add); 358 return 0; 359 } 360 361