builtin-probe.c (a36bf32e9e8a86f291f746b7f8292e042ee04a46) | builtin-probe.c (ef4a356574426877d569f8b6579325537eb7909b) |
---|---|
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 --- 22 unchanged lines hidden (view full) --- 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" | 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 --- 22 unchanged lines hidden (view full) --- 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" | 39#include "util/symbol.h" |
40#include "util/debug.h" 41#include "util/debugfs.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" | 42#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 */ 52static struct { | 43#include "util/probe-finder.h" 44#include "util/probe-event.h" 45 46#define MAX_PATH_LEN 256 47 48/* Session management structure */ 49static struct { |
53 bool need_dwarf; | |
54 bool list_events; 55 bool force_add; 56 bool show_lines; | 50 bool list_events; 51 bool force_add; 52 bool show_lines; |
57 int nr_probe; 58 struct probe_point probes[MAX_PROBES]; | 53 int nevents; 54 struct perf_probe_event events[MAX_PROBES]; |
59 struct strlist *dellist; | 55 struct strlist *dellist; |
60 struct map_groups kmap_groups; 61 struct map *kmaps[MAP__NR_TYPES]; | |
62 struct line_range line_range; | 56 struct line_range line_range; |
63} session; | 57 int max_probe_points; 58} params; |
64 65 66/* Parse an event definition. Note that any error must die. */ | 59 60 61/* Parse an event definition. Note that any error must die. */ |
67static void parse_probe_event(const char *str) | 62static int parse_probe_event(const char *str) |
68{ | 63{ |
69 struct probe_point *pp = &session.probes[session.nr_probe]; | 64 struct perf_probe_event *pev = ¶ms.events[params.nevents]; 65 int ret; |
70 | 66 |
71 pr_debug("probe-definition(%d): %s\n", session.nr_probe, str); 72 if (++session.nr_probe == MAX_PROBES) | 67 pr_debug("probe-definition(%d): %s\n", params.nevents, str); 68 if (++params.nevents == MAX_PROBES) |
73 die("Too many probes (> %d) are specified.", MAX_PROBES); 74 | 69 die("Too many probes (> %d) are specified.", MAX_PROBES); 70 |
75 /* Parse perf-probe event into probe_point */ 76 parse_perf_probe_event(str, pp, &session.need_dwarf); | 71 /* Parse a perf-probe command into event */ 72 ret = parse_perf_probe_command(str, pev); 73 pr_debug("%d arguments\n", pev->nargs); |
77 | 74 |
78 pr_debug("%d arguments\n", pp->nr_args); | 75 return ret; |
79} 80 | 76} 77 |
81static void parse_probe_event_argv(int argc, const char **argv) | 78static int parse_probe_event_argv(int argc, const char **argv) |
82{ | 79{ |
83 int i, len; | 80 int i, len, ret; |
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; | 81 char *buf; 82 83 /* Bind up rest arguments */ 84 len = 0; 85 for (i = 0; i < argc; i++) 86 len += strlen(argv[i]) + 1; |
90 buf = zalloc(len + 1); 91 if (!buf) 92 die("Failed to allocate memory for binding arguments."); | 87 buf = xzalloc(len + 1); |
93 len = 0; 94 for (i = 0; i < argc; i++) 95 len += sprintf(&buf[len], "%s ", argv[i]); | 88 len = 0; 89 for (i = 0; i < argc; i++) 90 len += sprintf(&buf[len], "%s ", argv[i]); |
96 parse_probe_event(buf); | 91 ret = parse_probe_event(buf); |
97 free(buf); | 92 free(buf); |
93 return ret; |
|
98} 99 100static int opt_add_probe_event(const struct option *opt __used, 101 const char *str, int unset __used) 102{ 103 if (str) | 94} 95 96static int opt_add_probe_event(const struct option *opt __used, 97 const char *str, int unset __used) 98{ 99 if (str) |
104 parse_probe_event(str); 105 return 0; | 100 return parse_probe_event(str); 101 else 102 return 0; |
106} 107 108static int opt_del_probe_event(const struct option *opt __used, 109 const char *str, int unset __used) 110{ 111 if (str) { | 103} 104 105static int opt_del_probe_event(const struct option *opt __used, 106 const char *str, int unset __used) 107{ 108 if (str) { |
112 if (!session.dellist) 113 session.dellist = strlist__new(true, NULL); 114 strlist__add(session.dellist, str); | 109 if (!params.dellist) 110 params.dellist = strlist__new(true, NULL); 111 strlist__add(params.dellist, str); |
115 } 116 return 0; 117} 118 | 112 } 113 return 0; 114} 115 |
119/* Currently just checking function name from symbol map */ 120static 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 131static 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 | 116#ifdef DWARF_SUPPORT |
142static int opt_show_lines(const struct option *opt __used, 143 const char *str, int unset __used) 144{ | 117static int opt_show_lines(const struct option *opt __used, 118 const char *str, int unset __used) 119{ |
120 int ret = 0; 121 |
|
145 if (str) | 122 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; | 123 ret = parse_line_range_desc(str, ¶ms.line_range); 124 INIT_LIST_HEAD(¶ms.line_range.line_list); 125 params.show_lines = true; 126 127 return ret; |
150} 151#endif 152 153static 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", | 128} 129#endif 130 131static const char * const probe_usage[] = { 132 "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", 133 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 134 "perf probe [<options>] --del '[GROUP:]EVENT' ...", 135 "perf probe --list", |
158#ifndef NO_DWARF_SUPPORT | 136#ifdef DWARF_SUPPORT |
159 "perf probe --line 'LINEDESC'", 160#endif 161 NULL 162}; 163 164static const struct option options[] = { | 137 "perf probe --line 'LINEDESC'", 138#endif 139 NULL 140}; 141 142static const struct option options[] = { |
165 OPT_BOOLEAN('v', "verbose", &verbose, | 143 OPT_INCR('v', "verbose", &verbose, |
166 "be more verbose (show parsed arguments, etc)"), | 144 "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, | 145 OPT_BOOLEAN('l', "list", ¶ms.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, | 146 "list up current probe events"), 147 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", 148 opt_del_probe_event), 149 OPT_CALLBACK('a', "add", NULL, |
176#ifdef NO_DWARF_SUPPORT 177 "[EVENT=]FUNC[+OFF|%return] [ARG ...]", 178#else | 150#ifdef DWARF_SUPPORT |
179 "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" | 151 "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" |
180 " [ARG ...]", | 152 " [[NAME=]ARG ...]", 153#else 154 "[EVENT=]FUNC[+OFF|%return] [[NAME=]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" | 155#endif 156 "probe point definition, where\n" 157 "\t\tGROUP:\tGroup name (optional)\n" 158 "\t\tEVENT:\tEvent name\n" 159 "\t\tFUNC:\tFunction name\n" 160 "\t\tOFF:\tOffset from function entry (in byte)\n" 161 "\t\t%return:\tPut the probe at function return\n" |
188#ifdef NO_DWARF_SUPPORT 189 "\t\tARG:\tProbe argument (only \n" 190#else | 162#ifdef DWARF_SUPPORT |
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" | 163 "\t\tSRC:\tSource code path\n" 164 "\t\tRL:\tRelative line number from function entry.\n" 165 "\t\tAL:\tAbsolute line number in file.\n" 166 "\t\tPT:\tLazy expression of line code.\n" 167 "\t\tARG:\tProbe argument (local variable name or\n" |
196#endif | |
197 "\t\t\tkprobe-tracer argument format.)\n", | 168 "\t\t\tkprobe-tracer argument format.)\n", |
169#else 170 "\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n", 171#endif |
|
198 opt_add_probe_event), | 172 opt_add_probe_event), |
199 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events" | 173 OPT_BOOLEAN('f', "force", ¶ms.force_add, "forcibly add events" |
200 " with existing name"), | 174 " with existing name"), |
201#ifndef NO_DWARF_SUPPORT | 175#ifdef DWARF_SUPPORT |
202 OPT_CALLBACK('L', "line", NULL, | 176 OPT_CALLBACK('L', "line", NULL, |
203 "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]", | 177 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", |
204 "Show source code lines.", opt_show_lines), | 178 "Show source code lines.", opt_show_lines), |
179 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 180 "file", "vmlinux pathname"), |
|
205#endif | 181#endif |
182 OPT__DRY_RUN(&probe_event_dry_run), 183 OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, 184 "Set how many probe points can be found for a probe."), |
|
206 OPT_END() 207}; 208 | 185 OPT_END() 186}; 187 |
209/* Initialize symbol maps for vmlinux */ 210static 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 | |
226int cmd_probe(int argc, const char **argv, const char *prefix __used) 227{ | 188int cmd_probe(int argc, const char **argv, const char *prefix __used) 189{ |
228 int i, ret; 229#ifndef NO_DWARF_SUPPORT 230 int fd; 231#endif 232 struct probe_point *pp; | 190 int ret; |
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 } | 191 192 argc = parse_options(argc, argv, options, probe_usage, 193 PARSE_OPT_STOP_AT_NON_OPTION); 194 if (argc > 0) { 195 if (strcmp(argv[0], "-") == 0) { 196 pr_warning(" Error: '-' is not supported.\n"); 197 usage_with_options(probe_usage, options); 198 } |
241 parse_probe_event_argv(argc, argv); | 199 ret = parse_probe_event_argv(argc, argv); 200 if (ret < 0) { 201 pr_err(" Error: Parse Error. (%d)\n", ret); 202 return ret; 203 } |
242 } 243 | 204 } 205 |
244 if ((!session.nr_probe && !session.dellist && !session.list_events && 245 !session.show_lines)) | 206 if (params.max_probe_points == 0) 207 params.max_probe_points = MAX_PROBES; 208 209 if ((!params.nevents && !params.dellist && !params.list_events && 210 !params.show_lines)) |
246 usage_with_options(probe_usage, options); 247 | 211 usage_with_options(probe_usage, options); 212 |
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"); | 213 if (params.list_events) { 214 if (params.nevents != 0 || params.dellist) { 215 pr_err(" Error: Don't use --list with --add/--del.\n"); |
255 usage_with_options(probe_usage, options); 256 } | 216 usage_with_options(probe_usage, options); 217 } |
257 if (session.show_lines) { 258 pr_warning(" Error: Don't use --list with --line.\n"); | 218 if (params.show_lines) { 219 pr_err(" Error: Don't use --list with --line.\n"); |
259 usage_with_options(probe_usage, options); 260 } | 220 usage_with_options(probe_usage, options); 221 } |
261 show_perf_probe_events(); 262 return 0; | 222 ret = show_perf_probe_events(); 223 if (ret < 0) 224 pr_err(" Error: Failed to show event list. (%d)\n", 225 ret); 226 return ret; |
263 } 264 | 227 } 228 |
265#ifndef NO_DWARF_SUPPORT 266 if (session.show_lines) { 267 if (session.nr_probe != 0 || session.dellist) { | 229#ifdef DWARF_SUPPORT 230 if (params.show_lines) { 231 if (params.nevents != 0 || params.dellist) { |
268 pr_warning(" Error: Don't use --line with" 269 " --add/--del.\n"); 270 usage_with_options(probe_usage, options); 271 } | 232 pr_warning(" Error: Don't use --line with" 233 " --add/--del.\n"); 234 usage_with_options(probe_usage, options); 235 } |
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; | 236 237 ret = show_line_range(¶ms.line_range); 238 if (ret < 0) 239 pr_err(" Error: Failed to show lines. (%d)\n", ret); 240 return ret; |
282 } 283#endif 284 | 241 } 242#endif 243 |
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; | 244 if (params.dellist) { 245 ret = del_perf_probe_events(params.dellist); 246 strlist__delete(params.dellist); 247 if (ret < 0) { 248 pr_err(" Error: Failed to delete events. (%d)\n", ret); 249 return ret; 250 } |
290 } 291 | 251 } 252 |
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]); | 253 if (params.nevents) { 254 ret = add_perf_probe_events(params.events, params.nevents, 255 params.force_add, 256 params.max_probe_points); 257 if (ret < 0) { 258 pr_err(" Error: Failed to add events. (%d)\n", ret); 259 return ret; |
325 } | 260 } |
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 } | 261 } |
336 close(fd); 337 338end_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 | 262 return 0; 263} 264 |