diff options
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r-- | tools/perf/util/probe-event.c | 802 |
1 files changed, 802 insertions, 0 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c new file mode 100644 index 000000000000..7c004b6ef24f --- /dev/null +++ b/tools/perf/util/probe-event.c | |||
@@ -0,0 +1,802 @@ | |||
1 | /* | ||
2 | * probe-event.c : perf-probe definition to kprobe_events format converter | ||
3 | * | ||
4 | * Written by Masami Hiramatsu <mhiramat@redhat.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #define _GNU_SOURCE | ||
23 | #include <sys/utsname.h> | ||
24 | #include <sys/types.h> | ||
25 | #include <sys/stat.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <errno.h> | ||
28 | #include <stdio.h> | ||
29 | #include <unistd.h> | ||
30 | #include <stdlib.h> | ||
31 | #include <string.h> | ||
32 | #include <stdarg.h> | ||
33 | #include <limits.h> | ||
34 | |||
35 | #undef _GNU_SOURCE | ||
36 | #include "event.h" | ||
37 | #include "string.h" | ||
38 | #include "strlist.h" | ||
39 | #include "debug.h" | ||
40 | #include "cache.h" | ||
41 | #include "color.h" | ||
42 | #include "parse-events.h" /* For debugfs_path */ | ||
43 | #include "probe-event.h" | ||
44 | |||
45 | #define MAX_CMDLEN 256 | ||
46 | #define MAX_PROBE_ARGS 128 | ||
47 | #define PERFPROBE_GROUP "probe" | ||
48 | |||
49 | #define semantic_error(msg ...) die("Semantic error :" msg) | ||
50 | |||
51 | /* If there is no space to write, returns -E2BIG. */ | ||
52 | static int e_snprintf(char *str, size_t size, const char *format, ...) | ||
53 | __attribute__((format(printf, 3, 4))); | ||
54 | |||
55 | static int e_snprintf(char *str, size_t size, const char *format, ...) | ||
56 | { | ||
57 | int ret; | ||
58 | va_list ap; | ||
59 | va_start(ap, format); | ||
60 | ret = vsnprintf(str, size, format, ap); | ||
61 | va_end(ap); | ||
62 | if (ret >= (int)size) | ||
63 | ret = -E2BIG; | ||
64 | return ret; | ||
65 | } | ||
66 | |||
67 | void parse_line_range_desc(const char *arg, struct line_range *lr) | ||
68 | { | ||
69 | const char *ptr; | ||
70 | char *tmp; | ||
71 | /* | ||
72 | * <Syntax> | ||
73 | * SRC:SLN[+NUM|-ELN] | ||
74 | * FUNC[:SLN[+NUM|-ELN]] | ||
75 | */ | ||
76 | ptr = strchr(arg, ':'); | ||
77 | if (ptr) { | ||
78 | lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0); | ||
79 | if (*tmp == '+') | ||
80 | lr->end = lr->start + (unsigned int)strtoul(tmp + 1, | ||
81 | &tmp, 0); | ||
82 | else if (*tmp == '-') | ||
83 | lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0); | ||
84 | else | ||
85 | lr->end = 0; | ||
86 | pr_debug("Line range is %u to %u\n", lr->start, lr->end); | ||
87 | if (lr->end && lr->start > lr->end) | ||
88 | semantic_error("Start line must be smaller" | ||
89 | " than end line."); | ||
90 | if (*tmp != '\0') | ||
91 | semantic_error("Tailing with invalid character '%d'.", | ||
92 | *tmp); | ||
93 | tmp = strndup(arg, (ptr - arg)); | ||
94 | } else | ||
95 | tmp = strdup(arg); | ||
96 | |||
97 | if (strchr(tmp, '.')) | ||
98 | lr->file = tmp; | ||
99 | else | ||
100 | lr->function = tmp; | ||
101 | } | ||
102 | |||
103 | /* Check the name is good for event/group */ | ||
104 | static bool check_event_name(const char *name) | ||
105 | { | ||
106 | if (!isalpha(*name) && *name != '_') | ||
107 | return false; | ||
108 | while (*++name != '\0') { | ||
109 | if (!isalpha(*name) && !isdigit(*name) && *name != '_') | ||
110 | return false; | ||
111 | } | ||
112 | return true; | ||
113 | } | ||
114 | |||
115 | /* Parse probepoint definition. */ | ||
116 | static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) | ||
117 | { | ||
118 | char *ptr, *tmp; | ||
119 | char c, nc = 0; | ||
120 | /* | ||
121 | * <Syntax> | ||
122 | * perf probe [EVENT=]SRC[:LN|;PTN] | ||
123 | * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT] | ||
124 | * | ||
125 | * TODO:Group name support | ||
126 | */ | ||
127 | |||
128 | ptr = strpbrk(arg, ";=@+%"); | ||
129 | if (ptr && *ptr == '=') { /* Event name */ | ||
130 | *ptr = '\0'; | ||
131 | tmp = ptr + 1; | ||
132 | ptr = strchr(arg, ':'); | ||
133 | if (ptr) /* Group name is not supported yet. */ | ||
134 | semantic_error("Group name is not supported yet."); | ||
135 | if (!check_event_name(arg)) | ||
136 | semantic_error("%s is bad for event name -it must " | ||
137 | "follow C symbol-naming rule.", arg); | ||
138 | pp->event = strdup(arg); | ||
139 | arg = tmp; | ||
140 | } | ||
141 | |||
142 | ptr = strpbrk(arg, ";:+@%"); | ||
143 | if (ptr) { | ||
144 | nc = *ptr; | ||
145 | *ptr++ = '\0'; | ||
146 | } | ||
147 | |||
148 | /* Check arg is function or file and copy it */ | ||
149 | if (strchr(arg, '.')) /* File */ | ||
150 | pp->file = strdup(arg); | ||
151 | else /* Function */ | ||
152 | pp->function = strdup(arg); | ||
153 | DIE_IF(pp->file == NULL && pp->function == NULL); | ||
154 | |||
155 | /* Parse other options */ | ||
156 | while (ptr) { | ||
157 | arg = ptr; | ||
158 | c = nc; | ||
159 | if (c == ';') { /* Lazy pattern must be the last part */ | ||
160 | pp->lazy_line = strdup(arg); | ||
161 | break; | ||
162 | } | ||
163 | ptr = strpbrk(arg, ";:+@%"); | ||
164 | if (ptr) { | ||
165 | nc = *ptr; | ||
166 | *ptr++ = '\0'; | ||
167 | } | ||
168 | switch (c) { | ||
169 | case ':': /* Line number */ | ||
170 | pp->line = strtoul(arg, &tmp, 0); | ||
171 | if (*tmp != '\0') | ||
172 | semantic_error("There is non-digit char" | ||
173 | " in line number."); | ||
174 | break; | ||
175 | case '+': /* Byte offset from a symbol */ | ||
176 | pp->offset = strtoul(arg, &tmp, 0); | ||
177 | if (*tmp != '\0') | ||
178 | semantic_error("There is non-digit character" | ||
179 | " in offset."); | ||
180 | break; | ||
181 | case '@': /* File name */ | ||
182 | if (pp->file) | ||
183 | semantic_error("SRC@SRC is not allowed."); | ||
184 | pp->file = strdup(arg); | ||
185 | DIE_IF(pp->file == NULL); | ||
186 | break; | ||
187 | case '%': /* Probe places */ | ||
188 | if (strcmp(arg, "return") == 0) { | ||
189 | pp->retprobe = 1; | ||
190 | } else /* Others not supported yet */ | ||
191 | semantic_error("%%%s is not supported.", arg); | ||
192 | break; | ||
193 | default: | ||
194 | DIE_IF("Program has a bug."); | ||
195 | break; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | /* Exclusion check */ | ||
200 | if (pp->lazy_line && pp->line) | ||
201 | semantic_error("Lazy pattern can't be used with line number."); | ||
202 | |||
203 | if (pp->lazy_line && pp->offset) | ||
204 | semantic_error("Lazy pattern can't be used with offset."); | ||
205 | |||
206 | if (pp->line && pp->offset) | ||
207 | semantic_error("Offset can't be used with line number."); | ||
208 | |||
209 | if (!pp->line && !pp->lazy_line && pp->file && !pp->function) | ||
210 | semantic_error("File always requires line number or " | ||
211 | "lazy pattern."); | ||
212 | |||
213 | if (pp->offset && !pp->function) | ||
214 | semantic_error("Offset requires an entry function."); | ||
215 | |||
216 | if (pp->retprobe && !pp->function) | ||
217 | semantic_error("Return probe requires an entry function."); | ||
218 | |||
219 | if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) | ||
220 | semantic_error("Offset/Line/Lazy pattern can't be used with " | ||
221 | "return probe."); | ||
222 | |||
223 | pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n", | ||
224 | pp->function, pp->file, pp->line, pp->offset, pp->retprobe, | ||
225 | pp->lazy_line); | ||
226 | } | ||
227 | |||
228 | /* Parse perf-probe event definition */ | ||
229 | void parse_perf_probe_event(const char *str, struct probe_point *pp, | ||
230 | bool *need_dwarf) | ||
231 | { | ||
232 | char **argv; | ||
233 | int argc, i; | ||
234 | |||
235 | *need_dwarf = false; | ||
236 | |||
237 | argv = argv_split(str, &argc); | ||
238 | if (!argv) | ||
239 | die("argv_split failed."); | ||
240 | if (argc > MAX_PROBE_ARGS + 1) | ||
241 | semantic_error("Too many arguments"); | ||
242 | |||
243 | /* Parse probe point */ | ||
244 | parse_perf_probe_probepoint(argv[0], pp); | ||
245 | if (pp->file || pp->line || pp->lazy_line) | ||
246 | *need_dwarf = true; | ||
247 | |||
248 | /* Copy arguments and ensure return probe has no C argument */ | ||
249 | pp->nr_args = argc - 1; | ||
250 | pp->args = zalloc(sizeof(char *) * pp->nr_args); | ||
251 | for (i = 0; i < pp->nr_args; i++) { | ||
252 | pp->args[i] = strdup(argv[i + 1]); | ||
253 | if (!pp->args[i]) | ||
254 | die("Failed to copy argument."); | ||
255 | if (is_c_varname(pp->args[i])) { | ||
256 | if (pp->retprobe) | ||
257 | semantic_error("You can't specify local" | ||
258 | " variable for kretprobe"); | ||
259 | *need_dwarf = true; | ||
260 | } | ||
261 | } | ||
262 | |||
263 | argv_free(argv); | ||
264 | } | ||
265 | |||
266 | /* Parse kprobe_events event into struct probe_point */ | ||
267 | void parse_trace_kprobe_event(const char *str, struct probe_point *pp) | ||
268 | { | ||
269 | char pr; | ||
270 | char *p; | ||
271 | int ret, i, argc; | ||
272 | char **argv; | ||
273 | |||
274 | pr_debug("Parsing kprobe_events: %s\n", str); | ||
275 | argv = argv_split(str, &argc); | ||
276 | if (!argv) | ||
277 | die("argv_split failed."); | ||
278 | if (argc < 2) | ||
279 | semantic_error("Too less arguments."); | ||
280 | |||
281 | /* Scan event and group name. */ | ||
282 | ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", | ||
283 | &pr, (float *)(void *)&pp->group, | ||
284 | (float *)(void *)&pp->event); | ||
285 | if (ret != 3) | ||
286 | semantic_error("Failed to parse event name: %s", argv[0]); | ||
287 | pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr); | ||
288 | |||
289 | pp->retprobe = (pr == 'r'); | ||
290 | |||
291 | /* Scan function name and offset */ | ||
292 | ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, | ||
293 | &pp->offset); | ||
294 | if (ret == 1) | ||
295 | pp->offset = 0; | ||
296 | |||
297 | /* kprobe_events doesn't have this information */ | ||
298 | pp->line = 0; | ||
299 | pp->file = NULL; | ||
300 | |||
301 | pp->nr_args = argc - 2; | ||
302 | pp->args = zalloc(sizeof(char *) * pp->nr_args); | ||
303 | for (i = 0; i < pp->nr_args; i++) { | ||
304 | p = strchr(argv[i + 2], '='); | ||
305 | if (p) /* We don't need which register is assigned. */ | ||
306 | *p = '\0'; | ||
307 | pp->args[i] = strdup(argv[i + 2]); | ||
308 | if (!pp->args[i]) | ||
309 | die("Failed to copy argument."); | ||
310 | } | ||
311 | |||
312 | argv_free(argv); | ||
313 | } | ||
314 | |||
315 | /* Synthesize only probe point (not argument) */ | ||
316 | int synthesize_perf_probe_point(struct probe_point *pp) | ||
317 | { | ||
318 | char *buf; | ||
319 | char offs[64] = "", line[64] = ""; | ||
320 | int ret; | ||
321 | |||
322 | pp->probes[0] = buf = zalloc(MAX_CMDLEN); | ||
323 | pp->found = 1; | ||
324 | if (!buf) | ||
325 | die("Failed to allocate memory by zalloc."); | ||
326 | if (pp->offset) { | ||
327 | ret = e_snprintf(offs, 64, "+%d", pp->offset); | ||
328 | if (ret <= 0) | ||
329 | goto error; | ||
330 | } | ||
331 | if (pp->line) { | ||
332 | ret = e_snprintf(line, 64, ":%d", pp->line); | ||
333 | if (ret <= 0) | ||
334 | goto error; | ||
335 | } | ||
336 | |||
337 | if (pp->function) | ||
338 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, | ||
339 | offs, pp->retprobe ? "%return" : "", line); | ||
340 | else | ||
341 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); | ||
342 | if (ret <= 0) { | ||
343 | error: | ||
344 | free(pp->probes[0]); | ||
345 | pp->probes[0] = NULL; | ||
346 | pp->found = 0; | ||
347 | } | ||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | int synthesize_perf_probe_event(struct probe_point *pp) | ||
352 | { | ||
353 | char *buf; | ||
354 | int i, len, ret; | ||
355 | |||
356 | len = synthesize_perf_probe_point(pp); | ||
357 | if (len < 0) | ||
358 | return 0; | ||
359 | |||
360 | buf = pp->probes[0]; | ||
361 | for (i = 0; i < pp->nr_args; i++) { | ||
362 | ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", | ||
363 | pp->args[i]); | ||
364 | if (ret <= 0) | ||
365 | goto error; | ||
366 | len += ret; | ||
367 | } | ||
368 | pp->found = 1; | ||
369 | |||
370 | return pp->found; | ||
371 | error: | ||
372 | free(pp->probes[0]); | ||
373 | pp->probes[0] = NULL; | ||
374 | |||
375 | return ret; | ||
376 | } | ||
377 | |||
378 | int synthesize_trace_kprobe_event(struct probe_point *pp) | ||
379 | { | ||
380 | char *buf; | ||
381 | int i, len, ret; | ||
382 | |||
383 | pp->probes[0] = buf = zalloc(MAX_CMDLEN); | ||
384 | if (!buf) | ||
385 | die("Failed to allocate memory by zalloc."); | ||
386 | ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset); | ||
387 | if (ret <= 0) | ||
388 | goto error; | ||
389 | len = ret; | ||
390 | |||
391 | for (i = 0; i < pp->nr_args; i++) { | ||
392 | ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", | ||
393 | pp->args[i]); | ||
394 | if (ret <= 0) | ||
395 | goto error; | ||
396 | len += ret; | ||
397 | } | ||
398 | pp->found = 1; | ||
399 | |||
400 | return pp->found; | ||
401 | error: | ||
402 | free(pp->probes[0]); | ||
403 | pp->probes[0] = NULL; | ||
404 | |||
405 | return ret; | ||
406 | } | ||
407 | |||
408 | static int open_kprobe_events(int flags, int mode) | ||
409 | { | ||
410 | char buf[PATH_MAX]; | ||
411 | int ret; | ||
412 | |||
413 | ret = e_snprintf(buf, PATH_MAX, "%s/../kprobe_events", debugfs_path); | ||
414 | if (ret < 0) | ||
415 | die("Failed to make kprobe_events path."); | ||
416 | |||
417 | ret = open(buf, flags, mode); | ||
418 | if (ret < 0) { | ||
419 | if (errno == ENOENT) | ||
420 | die("kprobe_events file does not exist -" | ||
421 | " please rebuild with CONFIG_KPROBE_EVENT."); | ||
422 | else | ||
423 | die("Could not open kprobe_events file: %s", | ||
424 | strerror(errno)); | ||
425 | } | ||
426 | return ret; | ||
427 | } | ||
428 | |||
429 | /* Get raw string list of current kprobe_events */ | ||
430 | static struct strlist *get_trace_kprobe_event_rawlist(int fd) | ||
431 | { | ||
432 | int ret, idx; | ||
433 | FILE *fp; | ||
434 | char buf[MAX_CMDLEN]; | ||
435 | char *p; | ||
436 | struct strlist *sl; | ||
437 | |||
438 | sl = strlist__new(true, NULL); | ||
439 | |||
440 | fp = fdopen(dup(fd), "r"); | ||
441 | while (!feof(fp)) { | ||
442 | p = fgets(buf, MAX_CMDLEN, fp); | ||
443 | if (!p) | ||
444 | break; | ||
445 | |||
446 | idx = strlen(p) - 1; | ||
447 | if (p[idx] == '\n') | ||
448 | p[idx] = '\0'; | ||
449 | ret = strlist__add(sl, buf); | ||
450 | if (ret < 0) | ||
451 | die("strlist__add failed: %s", strerror(-ret)); | ||
452 | } | ||
453 | fclose(fp); | ||
454 | |||
455 | return sl; | ||
456 | } | ||
457 | |||
458 | /* Free and zero clear probe_point */ | ||
459 | static void clear_probe_point(struct probe_point *pp) | ||
460 | { | ||
461 | int i; | ||
462 | |||
463 | if (pp->event) | ||
464 | free(pp->event); | ||
465 | if (pp->group) | ||
466 | free(pp->group); | ||
467 | if (pp->function) | ||
468 | free(pp->function); | ||
469 | if (pp->file) | ||
470 | free(pp->file); | ||
471 | if (pp->lazy_line) | ||
472 | free(pp->lazy_line); | ||
473 | for (i = 0; i < pp->nr_args; i++) | ||
474 | free(pp->args[i]); | ||
475 | if (pp->args) | ||
476 | free(pp->args); | ||
477 | for (i = 0; i < pp->found; i++) | ||
478 | free(pp->probes[i]); | ||
479 | memset(pp, 0, sizeof(*pp)); | ||
480 | } | ||
481 | |||
482 | /* Show an event */ | ||
483 | static void show_perf_probe_event(const char *event, const char *place, | ||
484 | struct probe_point *pp) | ||
485 | { | ||
486 | int i, ret; | ||
487 | char buf[128]; | ||
488 | |||
489 | ret = e_snprintf(buf, 128, "%s:%s", pp->group, event); | ||
490 | if (ret < 0) | ||
491 | die("Failed to copy event: %s", strerror(-ret)); | ||
492 | printf(" %-40s (on %s", buf, place); | ||
493 | |||
494 | if (pp->nr_args > 0) { | ||
495 | printf(" with"); | ||
496 | for (i = 0; i < pp->nr_args; i++) | ||
497 | printf(" %s", pp->args[i]); | ||
498 | } | ||
499 | printf(")\n"); | ||
500 | } | ||
501 | |||
502 | /* List up current perf-probe events */ | ||
503 | void show_perf_probe_events(void) | ||
504 | { | ||
505 | int fd; | ||
506 | struct probe_point pp; | ||
507 | struct strlist *rawlist; | ||
508 | struct str_node *ent; | ||
509 | |||
510 | setup_pager(); | ||
511 | memset(&pp, 0, sizeof(pp)); | ||
512 | |||
513 | fd = open_kprobe_events(O_RDONLY, 0); | ||
514 | rawlist = get_trace_kprobe_event_rawlist(fd); | ||
515 | close(fd); | ||
516 | |||
517 | strlist__for_each(ent, rawlist) { | ||
518 | parse_trace_kprobe_event(ent->s, &pp); | ||
519 | /* Synthesize only event probe point */ | ||
520 | synthesize_perf_probe_point(&pp); | ||
521 | /* Show an event */ | ||
522 | show_perf_probe_event(pp.event, pp.probes[0], &pp); | ||
523 | clear_probe_point(&pp); | ||
524 | } | ||
525 | |||
526 | strlist__delete(rawlist); | ||
527 | } | ||
528 | |||
529 | /* Get current perf-probe event names */ | ||
530 | static struct strlist *get_perf_event_names(int fd, bool include_group) | ||
531 | { | ||
532 | char buf[128]; | ||
533 | struct strlist *sl, *rawlist; | ||
534 | struct str_node *ent; | ||
535 | struct probe_point pp; | ||
536 | |||
537 | memset(&pp, 0, sizeof(pp)); | ||
538 | rawlist = get_trace_kprobe_event_rawlist(fd); | ||
539 | |||
540 | sl = strlist__new(true, NULL); | ||
541 | strlist__for_each(ent, rawlist) { | ||
542 | parse_trace_kprobe_event(ent->s, &pp); | ||
543 | if (include_group) { | ||
544 | if (e_snprintf(buf, 128, "%s:%s", pp.group, | ||
545 | pp.event) < 0) | ||
546 | die("Failed to copy group:event name."); | ||
547 | strlist__add(sl, buf); | ||
548 | } else | ||
549 | strlist__add(sl, pp.event); | ||
550 | clear_probe_point(&pp); | ||
551 | } | ||
552 | |||
553 | strlist__delete(rawlist); | ||
554 | |||
555 | return sl; | ||
556 | } | ||
557 | |||
558 | static void write_trace_kprobe_event(int fd, const char *buf) | ||
559 | { | ||
560 | int ret; | ||
561 | |||
562 | pr_debug("Writing event: %s\n", buf); | ||
563 | ret = write(fd, buf, strlen(buf)); | ||
564 | if (ret <= 0) | ||
565 | die("Failed to write event: %s", strerror(errno)); | ||
566 | } | ||
567 | |||
568 | static void get_new_event_name(char *buf, size_t len, const char *base, | ||
569 | struct strlist *namelist, bool allow_suffix) | ||
570 | { | ||
571 | int i, ret; | ||
572 | |||
573 | /* Try no suffix */ | ||
574 | ret = e_snprintf(buf, len, "%s", base); | ||
575 | if (ret < 0) | ||
576 | die("snprintf() failed: %s", strerror(-ret)); | ||
577 | if (!strlist__has_entry(namelist, buf)) | ||
578 | return; | ||
579 | |||
580 | if (!allow_suffix) { | ||
581 | pr_warning("Error: event \"%s\" already exists. " | ||
582 | "(Use -f to force duplicates.)\n", base); | ||
583 | die("Can't add new event."); | ||
584 | } | ||
585 | |||
586 | /* Try to add suffix */ | ||
587 | for (i = 1; i < MAX_EVENT_INDEX; i++) { | ||
588 | ret = e_snprintf(buf, len, "%s_%d", base, i); | ||
589 | if (ret < 0) | ||
590 | die("snprintf() failed: %s", strerror(-ret)); | ||
591 | if (!strlist__has_entry(namelist, buf)) | ||
592 | break; | ||
593 | } | ||
594 | if (i == MAX_EVENT_INDEX) | ||
595 | die("Too many events are on the same function."); | ||
596 | } | ||
597 | |||
598 | void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, | ||
599 | bool force_add) | ||
600 | { | ||
601 | int i, j, fd; | ||
602 | struct probe_point *pp; | ||
603 | char buf[MAX_CMDLEN]; | ||
604 | char event[64]; | ||
605 | struct strlist *namelist; | ||
606 | bool allow_suffix; | ||
607 | |||
608 | fd = open_kprobe_events(O_RDWR, O_APPEND); | ||
609 | /* Get current event names */ | ||
610 | namelist = get_perf_event_names(fd, false); | ||
611 | |||
612 | for (j = 0; j < nr_probes; j++) { | ||
613 | pp = probes + j; | ||
614 | if (!pp->event) | ||
615 | pp->event = strdup(pp->function); | ||
616 | if (!pp->group) | ||
617 | pp->group = strdup(PERFPROBE_GROUP); | ||
618 | DIE_IF(!pp->event || !pp->group); | ||
619 | /* If force_add is true, suffix search is allowed */ | ||
620 | allow_suffix = force_add; | ||
621 | for (i = 0; i < pp->found; i++) { | ||
622 | /* Get an unused new event name */ | ||
623 | get_new_event_name(event, 64, pp->event, namelist, | ||
624 | allow_suffix); | ||
625 | snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n", | ||
626 | pp->retprobe ? 'r' : 'p', | ||
627 | pp->group, event, | ||
628 | pp->probes[i]); | ||
629 | write_trace_kprobe_event(fd, buf); | ||
630 | printf("Added new event:\n"); | ||
631 | /* Get the first parameter (probe-point) */ | ||
632 | sscanf(pp->probes[i], "%s", buf); | ||
633 | show_perf_probe_event(event, buf, pp); | ||
634 | /* Add added event name to namelist */ | ||
635 | strlist__add(namelist, event); | ||
636 | /* | ||
637 | * Probes after the first probe which comes from same | ||
638 | * user input are always allowed to add suffix, because | ||
639 | * there might be several addresses corresponding to | ||
640 | * one code line. | ||
641 | */ | ||
642 | allow_suffix = true; | ||
643 | } | ||
644 | } | ||
645 | /* Show how to use the event. */ | ||
646 | printf("\nYou can now use it on all perf tools, such as:\n\n"); | ||
647 | printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event); | ||
648 | |||
649 | strlist__delete(namelist); | ||
650 | close(fd); | ||
651 | } | ||
652 | |||
653 | static void __del_trace_kprobe_event(int fd, struct str_node *ent) | ||
654 | { | ||
655 | char *p; | ||
656 | char buf[128]; | ||
657 | |||
658 | /* Convert from perf-probe event to trace-kprobe event */ | ||
659 | if (e_snprintf(buf, 128, "-:%s", ent->s) < 0) | ||
660 | die("Failed to copy event."); | ||
661 | p = strchr(buf + 2, ':'); | ||
662 | if (!p) | ||
663 | die("Internal error: %s should have ':' but not.", ent->s); | ||
664 | *p = '/'; | ||
665 | |||
666 | write_trace_kprobe_event(fd, buf); | ||
667 | printf("Remove event: %s\n", ent->s); | ||
668 | } | ||
669 | |||
670 | static void del_trace_kprobe_event(int fd, const char *group, | ||
671 | const char *event, struct strlist *namelist) | ||
672 | { | ||
673 | char buf[128]; | ||
674 | struct str_node *ent, *n; | ||
675 | int found = 0; | ||
676 | |||
677 | if (e_snprintf(buf, 128, "%s:%s", group, event) < 0) | ||
678 | die("Failed to copy event."); | ||
679 | |||
680 | if (strpbrk(buf, "*?")) { /* Glob-exp */ | ||
681 | strlist__for_each_safe(ent, n, namelist) | ||
682 | if (strglobmatch(ent->s, buf)) { | ||
683 | found++; | ||
684 | __del_trace_kprobe_event(fd, ent); | ||
685 | strlist__remove(namelist, ent); | ||
686 | } | ||
687 | } else { | ||
688 | ent = strlist__find(namelist, buf); | ||
689 | if (ent) { | ||
690 | found++; | ||
691 | __del_trace_kprobe_event(fd, ent); | ||
692 | strlist__remove(namelist, ent); | ||
693 | } | ||
694 | } | ||
695 | if (found == 0) | ||
696 | pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf); | ||
697 | } | ||
698 | |||
699 | void del_trace_kprobe_events(struct strlist *dellist) | ||
700 | { | ||
701 | int fd; | ||
702 | const char *group, *event; | ||
703 | char *p, *str; | ||
704 | struct str_node *ent; | ||
705 | struct strlist *namelist; | ||
706 | |||
707 | fd = open_kprobe_events(O_RDWR, O_APPEND); | ||
708 | /* Get current event names */ | ||
709 | namelist = get_perf_event_names(fd, true); | ||
710 | |||
711 | strlist__for_each(ent, dellist) { | ||
712 | str = strdup(ent->s); | ||
713 | if (!str) | ||
714 | die("Failed to copy event."); | ||
715 | pr_debug("Parsing: %s\n", str); | ||
716 | p = strchr(str, ':'); | ||
717 | if (p) { | ||
718 | group = str; | ||
719 | *p = '\0'; | ||
720 | event = p + 1; | ||
721 | } else { | ||
722 | group = "*"; | ||
723 | event = str; | ||
724 | } | ||
725 | pr_debug("Group: %s, Event: %s\n", group, event); | ||
726 | del_trace_kprobe_event(fd, group, event, namelist); | ||
727 | free(str); | ||
728 | } | ||
729 | strlist__delete(namelist); | ||
730 | close(fd); | ||
731 | } | ||
732 | |||
733 | #define LINEBUF_SIZE 256 | ||
734 | #define NR_ADDITIONAL_LINES 2 | ||
735 | |||
736 | static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num) | ||
737 | { | ||
738 | char buf[LINEBUF_SIZE]; | ||
739 | const char *color = PERF_COLOR_BLUE; | ||
740 | |||
741 | if (fgets(buf, LINEBUF_SIZE, fp) == NULL) | ||
742 | goto error; | ||
743 | if (!skip) { | ||
744 | if (show_num) | ||
745 | fprintf(stdout, "%7u %s", l, buf); | ||
746 | else | ||
747 | color_fprintf(stdout, color, " %s", buf); | ||
748 | } | ||
749 | |||
750 | while (strlen(buf) == LINEBUF_SIZE - 1 && | ||
751 | buf[LINEBUF_SIZE - 2] != '\n') { | ||
752 | if (fgets(buf, LINEBUF_SIZE, fp) == NULL) | ||
753 | goto error; | ||
754 | if (!skip) { | ||
755 | if (show_num) | ||
756 | fprintf(stdout, "%s", buf); | ||
757 | else | ||
758 | color_fprintf(stdout, color, "%s", buf); | ||
759 | } | ||
760 | } | ||
761 | return; | ||
762 | error: | ||
763 | if (feof(fp)) | ||
764 | die("Source file is shorter than expected."); | ||
765 | else | ||
766 | die("File read error: %s", strerror(errno)); | ||
767 | } | ||
768 | |||
769 | void show_line_range(struct line_range *lr) | ||
770 | { | ||
771 | unsigned int l = 1; | ||
772 | struct line_node *ln; | ||
773 | FILE *fp; | ||
774 | |||
775 | setup_pager(); | ||
776 | |||
777 | if (lr->function) | ||
778 | fprintf(stdout, "<%s:%d>\n", lr->function, | ||
779 | lr->start - lr->offset); | ||
780 | else | ||
781 | fprintf(stdout, "<%s:%d>\n", lr->file, lr->start); | ||
782 | |||
783 | fp = fopen(lr->path, "r"); | ||
784 | if (fp == NULL) | ||
785 | die("Failed to open %s: %s", lr->path, strerror(errno)); | ||
786 | /* Skip to starting line number */ | ||
787 | while (l < lr->start) | ||
788 | show_one_line(fp, l++, true, false); | ||
789 | |||
790 | list_for_each_entry(ln, &lr->line_list, list) { | ||
791 | while (ln->line > l) | ||
792 | show_one_line(fp, (l++) - lr->offset, false, false); | ||
793 | show_one_line(fp, (l++) - lr->offset, false, true); | ||
794 | } | ||
795 | |||
796 | if (lr->end == INT_MAX) | ||
797 | lr->end = l + NR_ADDITIONAL_LINES; | ||
798 | while (l < lr->end && !feof(fp)) | ||
799 | show_one_line(fp, (l++) - lr->offset, false, false); | ||
800 | |||
801 | fclose(fp); | ||
802 | } | ||