aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <rostedt@goodmis.org>2009-07-17 09:53:34 -0400
committerSteven Rostedt <rostedt@goodmis.org>2009-07-17 09:53:34 -0400
commitd78f5f2d3d250b695587d88a001da073d2e94ca9 (patch)
tree74b206f0b3ed2c51f1472a140d468f95f9ba1c54
Initial addition of trace-cmd files.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--Makefile20
-rw-r--r--parse-events.c2491
-rw-r--r--parse-events.h171
-rw-r--r--trace-cmd.c1143
-rw-r--r--trace-read.c604
5 files changed, 4429 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..538406c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,20 @@
1CC = gcc
2CFLAGS = -g -Wall # -O2
3INCLUDES = -I. -I/usr/local/include
4
5%.o: %.c
6 $(CC) -c $(CFLAGS) $(INCLUDES) $< -o $@
7
8TARGETS = trace-cmd
9
10all: $(TARGETS)
11
12parse-events.o:: parse-events.h
13trace-read.o:: parse-events.h
14trace-cmd.o:: parse-events.h
15
16trace-cmd: trace-cmd.o trace-read.o parse-events.o
17 $(CC) $^ -o $@
18
19clean:
20 $(RM) *.o *~ $(TARGETS)
diff --git a/parse-events.c b/parse-events.c
new file mode 100644
index 0000000..c5d8fe1
--- /dev/null
+++ b/parse-events.c
@@ -0,0 +1,2491 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <ctype.h>
5#include <errno.h>
6
7#include "parse-events.h"
8
9static char *input_buf;
10static unsigned long long input_buf_ptr;
11static unsigned long long input_buf_siz;
12
13static int cpus;
14static int long_size;
15
16static void init_input_buf(char *buf, unsigned long long size)
17{
18 input_buf = buf;
19 input_buf_siz = size;
20 input_buf_ptr = 0;
21}
22
23void breakpoint(void)
24{
25 static int x;
26 x++;
27}
28
29struct cmdline {
30 char *comm;
31 int pid;
32};
33
34static struct cmdline *cmdlines;
35static int cmdline_count;
36
37static int cmdline_cmp(const void *a, const void *b)
38{
39 const struct cmdline *ca = a;
40 const struct cmdline *cb = b;
41
42 if (ca->pid < cb->pid)
43 return -1;
44 if (ca->pid > cb->pid)
45 return 1;
46
47 return 0;
48}
49
50void parse_cmdlines(char *file, int size)
51{
52 struct cmdline_list {
53 struct cmdline_list *next;
54 char *comm;
55 int pid;
56 } *list = NULL, *item;
57 char *line;
58 char *next;
59 int i;
60
61 line = strtok_r(file, "\n", &next);
62 while (line) {
63 item = malloc_or_die(sizeof(*item));
64 sscanf(line, "%d %as", &item->pid,
65 &item->comm);
66 item->next = list;
67 list = item;
68 line = strtok_r(NULL, "\n", &next);
69 cmdline_count++;
70 }
71
72 cmdlines = malloc_or_die(sizeof(*cmdlines) * cmdline_count);
73
74 i = 0;
75 while (list) {
76 cmdlines[i].pid = list->pid;
77 cmdlines[i].comm = list->comm;
78 i++;
79 item = list;
80 list = list->next;
81 free(item);
82 }
83
84 qsort(cmdlines, cmdline_count, sizeof(*cmdlines), cmdline_cmp);
85}
86
87static char *find_cmdline(int pid)
88{
89 const struct cmdline *comm;
90 struct cmdline key;
91
92 if (!pid)
93 return "<idle>";
94
95 key.pid = pid;
96
97 comm = bsearch(&key, cmdlines, cmdline_count, sizeof(*cmdlines),
98 cmdline_cmp);
99
100 if (comm)
101 return comm->comm;
102 return "<...>";
103}
104
105static struct func_map {
106 unsigned long long addr;
107 char *func;
108 char *mod;
109} *func_list;
110static unsigned int func_count;
111
112static int func_cmp(const void *a, const void *b)
113{
114 const struct func_map *fa = a;
115 const struct func_map *fb = b;
116
117 if (fa->addr < fb->addr)
118 return -1;
119 if (fa->addr > fb->addr)
120 return 1;
121
122 return 0;
123}
124
125void parse_proc_kallsyms(char *file, unsigned int size)
126{
127 struct func_list {
128 struct func_list *next;
129 unsigned long long addr;
130 char *func;
131 char *mod;
132 } *list = NULL, *item;
133 char *line;
134 char *next;
135 char *addr_str;
136 char ch;
137 int ret;
138 int i;
139
140 line = strtok_r(file, "\n", &next);
141 while (line) {
142 item = malloc_or_die(sizeof(*item));
143 item->mod = NULL;
144 ret = sscanf(line, "%as %c %as\t[%as",
145 &addr_str,
146 &ch,
147 &item->func,
148 &item->mod);
149 item->addr = strtoull(addr_str, NULL, 16);
150 free(addr_str);
151
152 /* truncate the extra ']' */
153 if (item->mod)
154 item->mod[strlen(item->mod) - 1] = 0;
155
156
157 item->next = list;
158 list = item;
159 line = strtok_r(NULL, "\n", &next);
160 func_count++;
161 }
162
163 func_list = malloc_or_die(sizeof(*func_list) * func_count + 1);
164
165 i = 0;
166 while (list) {
167 func_list[i].func = list->func;
168 func_list[i].addr = list->addr;
169 func_list[i].mod = list->mod;
170 i++;
171 item = list;
172 list = list->next;
173 free(item);
174 }
175
176 qsort(func_list, func_count, sizeof(*func_list), func_cmp);
177
178 /*
179 * Add a special record at the end.
180 */
181 func_list[func_count].func = NULL;
182 func_list[func_count].addr = 0;
183 func_list[func_count].mod = NULL;
184}
185
186/*
187 * We are searching for a record in between, not an exact
188 * match.
189 */
190static int func_bcmp(const void *a, const void *b)
191{
192 const struct func_map *fa = a;
193 const struct func_map *fb = b;
194
195 if ((fa->addr == fb->addr) ||
196
197 (fa->addr > fb->addr &&
198 fa->addr < (fb+1)->addr))
199 return 0;
200
201 if (fa->addr < fb->addr)
202 return -1;
203
204 return 1;
205}
206
207static struct func_map *find_func(unsigned long long addr)
208{
209 struct func_map *func;
210 struct func_map key;
211
212 key.addr = addr;
213
214 func = bsearch(&key, func_list, func_count, sizeof(*func_list),
215 func_bcmp);
216
217 return func;
218}
219
220void print_funcs(void)
221{
222 int i;
223
224 for (i = 0; i < func_count; i++) {
225 printf("%016llx %s",
226 func_list[i].addr,
227 func_list[i].func);
228 if (func_list[i].mod)
229 printf(" [%s]\n", func_list[i].mod);
230 else
231 printf("\n");
232 }
233}
234
235struct event *alloc_event(void)
236{
237 struct event *event;
238
239 event = malloc_or_die(sizeof(*event));
240 memset(event, 0, sizeof(*event));
241
242 return event;
243}
244
245enum event_type {
246 EVENT_ERROR,
247 EVENT_NONE,
248 EVENT_SPACE,
249 EVENT_NEWLINE,
250 EVENT_ITEM,
251 EVENT_OP,
252 EVENT_DELIM,
253 EVENT_DQUOTE,
254 EVENT_SQUOTE,
255};
256
257static struct event *event_list;
258
259static void add_event(struct event *event)
260{
261 event->next = event_list;
262 event_list = event;
263}
264
265static int event_item_type(enum event_type type)
266{
267 switch (type) {
268 case EVENT_ITEM:
269 case EVENT_DQUOTE:
270 case EVENT_SQUOTE:
271 return 1;
272 default:
273 return 0;
274 }
275}
276
277void free_arg(struct print_arg *arg)
278{
279 if (!arg)
280 return;
281
282 switch (arg->type) {
283 case PRINT_ATOM:
284 if (arg->atom.atom)
285 free(arg->atom.atom);
286 break;
287 default:
288 /* todo */
289 break;
290 }
291
292 free(arg);
293}
294
295enum event_type get_type(int ch)
296{
297 if (ch == '\n')
298 return EVENT_NEWLINE;
299 if (isspace(ch))
300 return EVENT_SPACE;
301 if (isalnum(ch) || ch == '_')
302 return EVENT_ITEM;
303 if (ch == '\'')
304 return EVENT_SQUOTE;
305 if (ch == '"')
306 return EVENT_DQUOTE;
307 if (!isprint(ch))
308 return EVENT_NONE;
309 if (ch == '(' || ch == ')' || ch == ',')
310 return EVENT_DELIM;
311
312 return EVENT_OP;
313}
314
315static int __read_char(void)
316{
317 if (input_buf_ptr >= input_buf_siz)
318 return -1;
319
320 return input_buf[input_buf_ptr++];
321}
322
323static int __peak_char(void)
324{
325 if (input_buf_ptr >= input_buf_siz)
326 return -1;
327
328 return input_buf[input_buf_ptr];
329}
330
331enum event_type __read_token(char **tok)
332{
333 char buf[BUFSIZ];
334 int ch, last_ch, quote_ch, next_ch;
335 int i = 0;
336 int tok_size = 0;
337 enum event_type type;
338
339 *tok = NULL;
340
341
342 ch = __read_char();
343 if (ch < 0)
344 return EVENT_NONE;
345
346 type = get_type(ch);
347 if (type == EVENT_NONE)
348 return type;
349
350 buf[i++] = ch;
351
352 switch (type) {
353 case EVENT_NEWLINE:
354 case EVENT_DELIM:
355 *tok = malloc_or_die(2);
356 (*tok)[0] = ch;
357 (*tok)[1] = 0;
358 return type;
359
360 case EVENT_OP:
361 switch (ch) {
362 case '-':
363 next_ch = __peak_char();
364 if (next_ch == '>') {
365 buf[i++] = __read_char();
366 break;
367 }
368 /* fall through */
369 case '+':
370 case '|':
371 case '&':
372 case '>':
373 case '<':
374 case '!':
375 last_ch = ch;
376 ch = __peak_char();
377 if (ch != last_ch)
378 goto test_equal;
379 buf[i++] = __read_char();
380 switch (last_ch) {
381 case '>':
382 case '<':
383 goto test_equal;
384 }
385 break;
386 }
387 buf[i] = 0;
388 *tok = strdup(buf);
389 return type;
390
391 test_equal:
392 ch = __peak_char();
393 if (ch == '=')
394 buf[i++] = __read_char();
395 break;
396
397 case EVENT_DQUOTE:
398 case EVENT_SQUOTE:
399 /* don't keep quotes */
400 i--;
401 quote_ch = ch;
402 last_ch = 0;
403 do {
404 if (i == (BUFSIZ - 1)) {
405 buf[i] = 0;
406 if (*tok) {
407 *tok = realloc(*tok, tok_size + BUFSIZ);
408 if (!*tok)
409 return EVENT_NONE;
410 strcat(*tok, buf);
411 } else
412 *tok = strdup(buf);
413
414 if (!*tok)
415 return EVENT_NONE;
416 tok_size += BUFSIZ;
417 i = 0;
418 }
419 last_ch = ch;
420 ch = __read_char();
421 buf[i++] = ch;
422 } while (ch != quote_ch && last_ch != '\\');
423 /* remove the last quote */
424 i--;
425 goto out;
426 default:
427 break;
428 }
429
430 while (get_type(__peak_char()) == type) {
431 if (i == (BUFSIZ - 1)) {
432 buf[i] = 0;
433 if (*tok) {
434 *tok = realloc(*tok, tok_size + BUFSIZ);
435 if (!*tok)
436 return EVENT_NONE;
437 strcat(*tok, buf);
438 } else
439 *tok = strdup(buf);
440
441 if (!*tok)
442 return EVENT_NONE;
443 tok_size += BUFSIZ;
444 i = 0;
445 }
446 ch = __read_char();
447 buf[i++] = ch;
448 }
449
450 out:
451 buf[i] = 0;
452 if (*tok) {
453 *tok = realloc(*tok, tok_size + i);
454 if (!*tok)
455 return EVENT_NONE;
456 strcat(*tok, buf);
457 } else
458 *tok = strdup(buf);
459 if (!*tok)
460 return EVENT_NONE;
461
462 return type;
463}
464
465void free_token(char *tok)
466{
467 if (tok)
468 free(tok);
469}
470
471enum event_type read_token(char **tok)
472{
473 enum event_type type;
474
475 for (;;) {
476 type = __read_token(tok);
477 if (type != EVENT_SPACE)
478 return type;
479
480 free_token(*tok);
481 }
482
483 /* not reached */
484 return EVENT_NONE;
485}
486
487/* no newline */
488enum event_type read_token_item(char **tok)
489{
490 enum event_type type;
491
492 for (;;) {
493 type = __read_token(tok);
494 if (type != EVENT_SPACE && type != EVENT_NEWLINE)
495 return type;
496
497 free_token(*tok);
498 }
499
500 /* not reached */
501 return EVENT_NONE;
502}
503
504int test_type(enum event_type type, enum event_type expect)
505{
506 if (type != expect) {
507 die("Error: expected type %d but read %d",
508 expect, type);
509 return -1;
510 }
511 return 0;
512}
513
514int test_type_token(enum event_type type, char *token,
515 enum event_type expect, char *expect_tok)
516{
517 if (type != expect) {
518 die("Error: expected type %d but read %d",
519 expect, type);
520 return -1;
521 }
522
523 if (strcmp(token, expect_tok) != 0) {
524 die("Error: expected '%s' but read '%s'",
525 expect_tok, token);
526 return -1;
527 }
528 return 0;
529}
530
531int __read_expect_type(enum event_type expect, char **tok, int newline_ok)
532{
533 enum event_type type;
534
535 if (newline_ok)
536 type = read_token(tok);
537 else
538 type = read_token_item(tok);
539 return test_type(type, expect);
540}
541
542int read_expect_type(enum event_type expect, char **tok)
543{
544 return __read_expect_type(expect, tok, 1);
545}
546
547int read_expect_type_item(enum event_type expect, char **tok)
548{
549 return __read_expect_type(expect, tok, 0);
550}
551
552int __read_expected(enum event_type expect, char *str, int newline_ok)
553{
554 enum event_type type;
555 char *token;
556 int ret;
557
558 if (newline_ok)
559 type = read_token(&token);
560 else
561 type = read_token_item(&token);
562
563 ret = test_type_token(type, token, expect, str);
564
565 free_token(token);
566
567 return 0;
568}
569
570int read_expected(enum event_type expect, char *str)
571{
572 return __read_expected(expect, str, 1);
573}
574
575int read_expected_item(enum event_type expect, char *str)
576{
577 return __read_expected(expect, str, 0);
578}
579
580char *event_read_name(void)
581{
582 char *token;
583
584 if (read_expected(EVENT_ITEM, "name") < 0)
585 return NULL;
586
587 if (read_expected(EVENT_OP, ":") < 0)
588 return NULL;
589
590 if (read_expect_type(EVENT_ITEM, &token) < 0)
591 goto fail;
592
593 return token;
594
595 fail:
596 free_token(token);
597 return NULL;
598}
599
600int event_read_id(void)
601{
602 char *token;
603 int id;
604
605 if (read_expected_item(EVENT_ITEM, "ID") < 0)
606 return -1;
607
608 if (read_expected(EVENT_OP, ":") < 0)
609 return -1;
610
611 if (read_expect_type(EVENT_ITEM, &token) < 0)
612 goto fail;
613
614 id = strtoul(token, NULL, 0);
615 free_token(token);
616 return id;
617
618 fail:
619 free_token(token);
620 return -1;
621}
622
623int event_read_fields(struct event *event, struct format_field **fields)
624{
625 struct format_field *field = NULL;
626 enum event_type type;
627 char *token;
628 char *last_token;
629 int count = 0;
630
631 do {
632 type = read_token(&token);
633 if (type == EVENT_NEWLINE) {
634 free_token(token);
635 return count;
636 }
637
638 count++;
639
640 if (test_type_token(type, token, EVENT_ITEM, "field"))
641 goto fail;
642 free_token(token);
643
644 type = read_token(&token);
645 /*
646 * The ftrace fields may still use the "special" name.
647 * Just ignore it.
648 */
649 if (event->flags & EVENT_FL_ISFTRACE &&
650 type == EVENT_ITEM && strcmp(token, "special") == 0) {
651 free_token(token);
652 type = read_token(&token);
653 }
654
655 if (test_type_token(type, token, EVENT_OP, ":") < 0)
656 return -1;
657
658 if (read_expect_type(EVENT_ITEM, &token) < 0)
659 goto fail;
660
661 last_token = token;
662
663 field = malloc_or_die(sizeof(*field));
664 memset(field, 0, sizeof(*field));
665
666 /* read the rest of the type */
667 for (;;) {
668 type = read_token(&token);
669 if (type == EVENT_ITEM ||
670 (type == EVENT_OP && strcmp(token, "*") == 0) ||
671 /*
672 * Some of the ftrace fields are broken and have
673 * an illegal "." in them.
674 */
675 (event->flags & EVENT_FL_ISFTRACE &&
676 type == EVENT_OP && strcmp(token, ".") == 0)) {
677
678 if (strcmp(token, "*") == 0)
679 field->flags |= FIELD_IS_POINTER;
680
681 if (field->type) {
682 field->type = realloc(field->type,
683 strlen(field->type) +
684 strlen(last_token) + 2);
685 strcat(field->type, " ");
686 strcat(field->type, last_token);
687 } else
688 field->type = last_token;
689 last_token = token;
690 continue;
691 }
692
693 break;
694 }
695
696 if (!field->type) {
697 die("no type found");
698 goto fail;
699 }
700 field->name = last_token;
701
702 if (test_type(type, EVENT_OP))
703 goto fail;
704
705 if (strcmp(token, "[") == 0) {
706 field->flags |= FIELD_IS_ARRAY;
707 /* add brackets to type */
708 do {
709 field->type = realloc(field->type,
710 strlen(field->type) +
711 strlen(token) + 1);
712 strcat(field->type, token);
713 free_token(token);
714 type = read_token(&token);
715 if (type == EVENT_NONE) {
716 die("failed to find token");
717 goto fail;
718 }
719 } while (type != EVENT_OP || strcmp(token, "]") != 0);
720 field->type = realloc(field->type,
721 strlen(field->type) + 2);
722 strcat(field->type, "]");
723 free_token(token);
724 type = read_token(&token);
725 }
726
727 if (test_type_token(type, token, EVENT_OP, ";"))
728 goto fail;
729 free_token(token);
730
731 if (read_expected(EVENT_ITEM, "offset") < 0)
732 goto fail_expect;
733
734 if (read_expected(EVENT_OP, ":") < 0)
735 goto fail_expect;
736
737 if (read_expect_type(EVENT_ITEM, &token))
738 goto fail;
739 field->offset = strtoul(token, NULL, 0);
740 free_token(token);
741
742 if (read_expected(EVENT_OP, ";") < 0)
743 goto fail_expect;
744
745 if (read_expected(EVENT_ITEM, "size") < 0)
746 goto fail_expect;
747
748 if (read_expected(EVENT_OP, ":") < 0)
749 goto fail_expect;
750
751 if (read_expect_type(EVENT_ITEM, &token))
752 goto fail;
753 field->size = strtoul(token, NULL, 0);
754 free_token(token);
755
756 if (read_expected(EVENT_OP, ";") < 0)
757 goto fail_expect;
758
759 if (read_expect_type(EVENT_NEWLINE, &token) < 0)
760 goto fail;
761 free_token(token);
762
763 *fields = field;
764 fields = &field->next;
765
766 } while (1);
767
768 return 0;
769
770fail:
771 free_token(token);
772fail_expect:
773 if (field)
774 free(field);
775 return -1;
776}
777
778int event_read_format(struct event *event)
779{
780 char *token;
781 int ret;
782
783 if (read_expected_item(EVENT_ITEM, "format") < 0)
784 return -1;
785
786 if (read_expected(EVENT_OP, ":") < 0)
787 return -1;
788
789 if (read_expect_type(EVENT_NEWLINE, &token))
790 goto fail;
791 free_token(token);
792
793 ret = event_read_fields(event, &event->format.common_fields);
794 if (ret < 0)
795 return ret;
796 event->format.nr_common = ret;
797
798 ret = event_read_fields(event, &event->format.fields);
799 if (ret < 0)
800 return ret;
801 event->format.nr_fields = ret;
802
803 return 0;
804
805 fail:
806 free_token(token);
807 return -1;
808}
809
810enum event_type
811process_arg_token(struct event *event, struct print_arg *arg,
812 char **tok, enum event_type type);
813
814enum event_type
815process_arg(struct event *event, struct print_arg *arg, char **tok)
816{
817 enum event_type type;
818 char *token;
819
820 type = read_token(&token);
821 *tok = token;
822
823 return process_arg_token(event, arg, tok, type);
824}
825
826enum event_type
827process_cond(struct event *event, struct print_arg *top, char **tok)
828{
829 struct print_arg *arg, *left, *right;
830 enum event_type type;
831 char *token = NULL;
832
833 arg = malloc_or_die(sizeof(*arg));
834 memset(arg, 0, sizeof(*arg));
835
836 left = malloc_or_die(sizeof(*left));
837
838 right = malloc_or_die(sizeof(*right));
839
840 arg->type = PRINT_OP;
841 arg->op.left = left;
842 arg->op.right = right;
843
844 *tok = NULL;
845 type = process_arg(event, left, &token);
846 if (test_type_token(type, token, EVENT_OP, ":"))
847 goto out_free;
848
849 arg->op.op = token;
850
851 type = process_arg(event, right, &token);
852
853 top->op.right = arg;
854
855 *tok = token;
856 return type;
857
858out_free:
859 free_token(*tok);
860 free(right);
861 free(left);
862 free_arg(arg);
863 return EVENT_ERROR;
864}
865
866static int get_op_prio(char *op)
867{
868 if (!op[1]) {
869 switch (op[0]) {
870 case '*':
871 case '/':
872 case '%':
873 return 6;
874 case '+':
875 case '-':
876 return 7;
877 /* '>>' and '<<' are 8 */
878 case '<':
879 case '>':
880 return 9;
881 /* '==' and '!=' are 10 */
882 case '&':
883 return 11;
884 case '^':
885 return 12;
886 case '|':
887 return 13;
888 case '?':
889 return 16;
890 default:
891 die("unknown op '%c'", op[0]);
892 return -1;
893 }
894 } else {
895 if (strcmp(op, "++") == 0 ||
896 strcmp(op, "--") == 0) {
897 return 3;
898 } else if (strcmp(op, ">>") == 0 ||
899 strcmp(op, "<<") == 0) {
900 return 8;
901 } else if (strcmp(op, ">=") == 0 ||
902 strcmp(op, "<=") == 0) {
903 return 9;
904 } else if (strcmp(op, "==") == 0 ||
905 strcmp(op, "!=") == 0) {
906 return 10;
907 } else if (strcmp(op, "&&") == 0) {
908 return 14;
909 } else if (strcmp(op, "||") == 0) {
910 return 15;
911 } else {
912 die("unknown op '%s'", op);
913 return -1;
914 }
915 }
916}
917
918static void set_op_prio(struct print_arg *arg)
919{
920
921 /* single ops are the greatest */
922 if (!arg->op.left || arg->op.left->type == PRINT_NULL) {
923 arg->op.prio = 0;
924 return;
925 }
926
927 arg->op.prio = get_op_prio(arg->op.op);
928}
929
930enum event_type
931process_op(struct event *event, struct print_arg *arg, char **tok)
932{
933 struct print_arg *left, *right;
934 enum event_type type;
935 char *token;
936
937 /* the op is passed in via tok */
938 token = *tok;
939
940 if (arg->type == PRINT_OP && !arg->op.left) {
941 /* handle single op */
942 if (token[1]) {
943 die("bad op token %s", token);
944 return EVENT_ERROR;
945 }
946 switch (token[0]) {
947 case '!':
948 case '+':
949 case '-':
950 break;
951 default:
952 die("bad op token %s", token);
953 return EVENT_ERROR;
954 }
955
956 /* make an empty left */
957 left = malloc_or_die(sizeof(*left));
958 left->type = PRINT_NULL;
959 arg->op.left = left;
960
961 right = malloc_or_die(sizeof(*right));
962 arg->op.right = right;
963
964 type = process_arg(event, right, tok);
965
966 } else if (strcmp(token, "?") == 0) {
967
968 left = malloc_or_die(sizeof(*left));
969 /* copy the top arg to the left */
970 *left = *arg;
971
972 arg->type = PRINT_OP;
973 arg->op.op = token;
974 arg->op.left = left;
975 arg->op.prio = 0;
976
977 type = process_cond(event, arg, tok);
978
979 } else if (strcmp(token, ">>") == 0 ||
980 strcmp(token, "<<") == 0 ||
981 strcmp(token, "&") == 0 ||
982 strcmp(token, "|") == 0 ||
983 strcmp(token, "&&") == 0 ||
984 strcmp(token, "||") == 0 ||
985 strcmp(token, "-") == 0 ||
986 strcmp(token, "+") == 0 ||
987 strcmp(token, "*") == 0 ||
988 strcmp(token, "^") == 0 ||
989 strcmp(token, "/") == 0) {
990
991 left = malloc_or_die(sizeof(*left));
992
993 /* copy the top arg to the left */
994 *left = *arg;
995
996 arg->type = PRINT_OP;
997 arg->op.op = token;
998 arg->op.left = left;
999
1000 set_op_prio(arg);
1001
1002 right = malloc_or_die(sizeof(*right));
1003
1004 type = process_arg(event, right, tok);
1005
1006 arg->op.right = right;
1007
1008 } else {
1009 die("unknown op '%s'", token);
1010 /* the arg is now the left side */
1011 return EVENT_NONE;
1012 }
1013
1014
1015 if (type == EVENT_OP) {
1016 int prio;
1017
1018 /* higher prios need to be closer to the root */
1019 prio = get_op_prio(*tok);
1020
1021 if (prio > arg->op.prio)
1022 return process_op(event, arg, tok);
1023
1024 return process_op(event, right, tok);
1025 }
1026
1027 return type;
1028}
1029
1030enum event_type
1031process_entry(struct event *event, struct print_arg *arg,
1032 char **tok)
1033{
1034 enum event_type type;
1035 char *field;
1036 char *token;
1037
1038 if (read_expected(EVENT_OP, "->") < 0)
1039 return EVENT_ERROR;
1040
1041 if (read_expect_type(EVENT_ITEM, &token) < 0)
1042 goto fail;
1043 field = token;
1044
1045 arg->type = PRINT_FIELD;
1046 arg->field.name = field;
1047
1048 type = read_token(&token);
1049 *tok = token;
1050
1051 return type;
1052
1053fail:
1054 free_token(token);
1055 return EVENT_ERROR;
1056}
1057
1058static char *arg_eval (struct print_arg *arg);
1059
1060static long long arg_num_eval(struct print_arg *arg)
1061{
1062 long long left, right;
1063 long long val;
1064
1065 switch (arg->type) {
1066 case PRINT_ATOM:
1067 val = strtoll(arg->atom.atom, NULL, 0);
1068 break;
1069 case PRINT_TYPE:
1070 val = arg_num_eval(arg->typecast.item);
1071 break;
1072 case PRINT_OP:
1073 switch (arg->op.op[0]) {
1074 case '|':
1075 left = arg_num_eval(arg->op.left);
1076 right = arg_num_eval(arg->op.right);
1077 if (arg->op.op[1])
1078 val = left || right;
1079 else
1080 val = left | right;
1081 break;
1082 case '&':
1083 left = arg_num_eval(arg->op.left);
1084 right = arg_num_eval(arg->op.right);
1085 if (arg->op.op[1])
1086 val = left && right;
1087 else
1088 val = left & right;
1089 break;
1090 case '<':
1091 left = arg_num_eval(arg->op.left);
1092 right = arg_num_eval(arg->op.right);
1093 switch (arg->op.op[1]) {
1094 case 0:
1095 val = left < right;
1096 break;
1097 case '<':
1098 val = left << right;
1099 break;
1100 case '=':
1101 val = left <= right;
1102 break;
1103 default:
1104 die("unknown op '%s'", arg->op.op);
1105 }
1106 break;
1107 case '>':
1108 left = arg_num_eval(arg->op.left);
1109 right = arg_num_eval(arg->op.right);
1110 switch (arg->op.op[1]) {
1111 case 0:
1112 val = left > right;
1113 break;
1114 case '>':
1115 val = left >> right;
1116 break;
1117 case '=':
1118 val = left >= right;
1119 break;
1120 default:
1121 die("unknown op '%s'", arg->op.op);
1122 }
1123 break;
1124 case '=':
1125 if (arg->op.op[1] != '=')
1126 die("unknown op '%s'", arg->op.op);
1127
1128 val = left == right;
1129 break;
1130 default:
1131 die("unknown op '%s'", arg->op.op);
1132 }
1133 break;
1134 default:
1135 die("invalid eval type %d", arg->type);
1136
1137 }
1138 return val;
1139}
1140
1141static char *arg_eval (struct print_arg *arg)
1142{
1143 long long val;
1144 static char buf[20];
1145
1146 switch (arg->type) {
1147 case PRINT_ATOM:
1148 return arg->atom.atom;
1149 case PRINT_TYPE:
1150 return arg_eval(arg->typecast.item);
1151 case PRINT_OP:
1152 val = arg_num_eval(arg);
1153 sprintf(buf, "%lld", val);
1154 return buf;
1155
1156 default:
1157 die("invalid eval type %d", arg->type);
1158 break;
1159 }
1160
1161 return NULL;
1162}
1163
1164enum event_type
1165process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1166{
1167 enum event_type type;
1168 struct print_arg *arg = NULL;
1169 struct print_flag_sym *field;
1170 char *token = NULL;
1171 char *value;
1172
1173 do {
1174 free_token(token);
1175 type = read_token_item(&token);
1176 if (test_type_token(type, token, EVENT_OP, "{"))
1177 break;
1178
1179 arg = malloc_or_die(sizeof(*arg));
1180
1181 free_token(token);
1182 type = process_arg(event, arg, &token);
1183 if (test_type_token(type, token, EVENT_DELIM, ","))
1184 goto out_free;
1185
1186 field = malloc_or_die(sizeof(*field));
1187 memset(field, 0, sizeof(field));
1188
1189 value = arg_eval(arg);
1190 field->value = strdup(value);
1191
1192 free_token(token);
1193 type = process_arg(event, arg, &token);
1194 if (test_type_token(type, token, EVENT_OP, "}"))
1195 goto out_free;
1196
1197 value = arg_eval(arg);
1198 field->str = strdup(value);
1199 free_arg(arg);
1200 arg = NULL;
1201
1202 *list = field;
1203 list = &field->next;
1204
1205 free_token(token);
1206 type = read_token_item(&token);
1207 } while (type == EVENT_DELIM && strcmp(token, ",") == 0);
1208
1209 *tok = token;
1210 return type;
1211
1212out_free:
1213 free_arg(arg);
1214 free_token(token);
1215
1216 return EVENT_ERROR;
1217}
1218
1219enum event_type
1220process_flags(struct event *event, struct print_arg *arg, char **tok)
1221{
1222 struct print_arg *field;
1223 enum event_type type;
1224 char *token;
1225
1226 memset(arg, 0, sizeof(*arg));
1227 arg->type = PRINT_FLAGS;
1228
1229 if (read_expected_item(EVENT_DELIM, "(") < 0)
1230 return EVENT_ERROR;
1231
1232 field = malloc_or_die(sizeof(*field));
1233
1234 type = process_arg(event, field, &token);
1235 if (test_type_token(type, token, EVENT_DELIM, ","))
1236 goto out_free;
1237
1238 arg->flags.field = field;
1239
1240 type = read_token_item(&token);
1241 if (event_item_type(type)) {
1242 arg->flags.delim = token;
1243 type = read_token_item(&token);
1244 }
1245
1246 if (test_type_token(type, token, EVENT_DELIM, ","))
1247 goto out_free;
1248
1249 type = process_fields(event, &arg->flags.flags, &token);
1250 if (test_type_token(type, token, EVENT_DELIM, ")"))
1251 goto out_free;
1252
1253 free_token(token);
1254 type = read_token_item(tok);
1255 return type;
1256
1257out_free:
1258 free_token(token);
1259 return EVENT_ERROR;
1260}
1261
1262enum event_type
1263process_symbols(struct event *event, struct print_arg *arg, char **tok)
1264{
1265 struct print_arg *field;
1266 enum event_type type;
1267 char *token;
1268
1269 memset(arg, 0, sizeof(*arg));
1270 arg->type = PRINT_SYMBOL;
1271
1272 if (read_expected_item(EVENT_DELIM, "(") < 0)
1273 return EVENT_ERROR;
1274
1275 field = malloc_or_die(sizeof(*field));
1276
1277 type = process_arg(event, field, &token);
1278 if (test_type_token(type, token, EVENT_DELIM, ","))
1279 goto out_free;
1280
1281 arg->symbol.field = field;
1282
1283 type = process_fields(event, &arg->symbol.symbols, &token);
1284 if (test_type_token(type, token, EVENT_DELIM, ")"))
1285 goto out_free;
1286
1287 free_token(token);
1288 type = read_token_item(tok);
1289 return type;
1290
1291out_free:
1292 free_token(token);
1293 return EVENT_ERROR;
1294}
1295
1296enum event_type
1297process_paren(struct event *event, struct print_arg *arg, char **tok)
1298{
1299 struct print_arg *item_arg;
1300 enum event_type type;
1301 char *token;
1302
1303 type = process_arg(event, arg, &token);
1304
1305 if (type == EVENT_ERROR)
1306 return EVENT_ERROR;
1307
1308 if (type == EVENT_OP)
1309 type = process_op(event, arg, &token);
1310
1311 if (type == EVENT_ERROR)
1312 return EVENT_ERROR;
1313
1314 if (test_type_token(type, token, EVENT_DELIM, ")")) {
1315 free_token(token);
1316 return EVENT_ERROR;
1317 }
1318
1319 free_token(token);
1320 type = read_token_item(&token);
1321
1322 /*
1323 * If the next token is an item or another open paren, then
1324 * this was a typecast.
1325 */
1326 if (event_item_type(type) ||
1327 (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
1328
1329 /* make this a typecast and contine */
1330
1331 /* prevous must be an atom */
1332 if (arg->type != PRINT_ATOM)
1333 die("previous needed to be PRINT_ATOM");
1334
1335 item_arg = malloc_or_die(sizeof(*item_arg));
1336
1337 arg->type = PRINT_TYPE;
1338 arg->typecast.type = arg->atom.atom;
1339 arg->typecast.item = item_arg;
1340 type = process_arg_token(event, item_arg, &token, type);
1341
1342 }
1343
1344 *tok = token;
1345 return type;
1346}
1347
1348
1349enum event_type
1350process_str(struct event *event, struct print_arg *arg, char **tok)
1351{
1352 enum event_type type;
1353 char *token;
1354
1355 if (read_expected(EVENT_DELIM, "(") < 0)
1356 return EVENT_ERROR;
1357
1358 if (read_expect_type(EVENT_ITEM, &token) < 0)
1359 goto fail;
1360
1361 arg->type = PRINT_STRING;
1362 arg->string.string = token;
1363
1364 if (read_expected(EVENT_DELIM, ")") < 0)
1365 return EVENT_ERROR;
1366
1367 type = read_token(&token);
1368 *tok = token;
1369
1370 return type;
1371fail:
1372 free_token(token);
1373 return EVENT_ERROR;
1374}
1375
1376enum event_type
1377process_arg_token(struct event *event, struct print_arg *arg,
1378 char **tok, enum event_type type)
1379{
1380 char *token;
1381 char *atom;
1382
1383 token = *tok;
1384
1385 switch (type) {
1386 case EVENT_ITEM:
1387 if (strcmp(token, "REC") == 0) {
1388 free_token(token);
1389 type = process_entry(event, arg, &token);
1390 } else if (strcmp(token, "__print_flags") == 0) {
1391 free_token(token);
1392 type = process_flags(event, arg, &token);
1393 } else if (strcmp(token, "__print_symbolic") == 0) {
1394 free_token(token);
1395 type = process_symbols(event, arg, &token);
1396 } else if (strcmp(token, "__get_str") == 0) {
1397 free_token(token);
1398 type = process_str(event, arg, &token);
1399 } else {
1400 atom = token;
1401 /* test the next token */
1402 type = read_token_item(&token);
1403
1404 /* atoms can be more than one token long */
1405 while (type == EVENT_ITEM) {
1406 atom = realloc(atom, strlen(atom) + strlen(token) + 2);
1407 strcat(atom, " ");
1408 strcat(atom, token);
1409 free_token(token);
1410 type = read_token_item(&token);
1411 }
1412
1413 /* todo, test for function */
1414
1415 arg->type = PRINT_ATOM;
1416 arg->atom.atom = atom;
1417 }
1418 break;
1419 case EVENT_DQUOTE:
1420 case EVENT_SQUOTE:
1421 arg->type = PRINT_ATOM;
1422 arg->atom.atom = token;
1423 type = read_token_item(&token);
1424 break;
1425 case EVENT_DELIM:
1426 if (strcmp(token, "(") == 0) {
1427 free_token(token);
1428 type = process_paren(event, arg, &token);
1429 break;
1430 }
1431 case EVENT_OP:
1432 /* handle single ops */
1433 arg->type = PRINT_OP;
1434 arg->op.op = token;
1435 arg->op.left = NULL;
1436 type = process_op(event, arg, &token);
1437
1438 break;
1439 default:
1440 die("unexpected type %d", type);
1441 }
1442 *tok = token;
1443
1444 return type;
1445}
1446
1447int event_read_print_args(struct event *event, struct print_arg **list)
1448{
1449 enum event_type type;
1450 struct print_arg *arg;
1451 char *token;
1452 int args = 0;
1453
1454 do {
1455 arg = malloc_or_die(sizeof(*arg));
1456 memset(arg, 0, sizeof(*arg));
1457
1458 type = process_arg(event, arg, &token);
1459
1460 if (type == EVENT_ERROR) {
1461 free_arg(arg);
1462 return -1;
1463 }
1464
1465 *list = arg;
1466 args++;
1467
1468 if (type == EVENT_OP) {
1469 type = process_op(event, arg, &token);
1470 list = &arg->next;
1471 continue;
1472 }
1473
1474 if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
1475 free_token(token);
1476 *list = arg;
1477 list = &arg->next;
1478 continue;
1479 }
1480 break;
1481 } while (type != EVENT_NONE);
1482
1483 if (type != EVENT_NONE)
1484 free_token(token);
1485
1486 return args;
1487}
1488
1489int event_read_print(struct event *event)
1490{
1491 enum event_type type;
1492 char *token;
1493 int ret;
1494
1495 if (read_expected_item(EVENT_ITEM, "print") < 0)
1496 return -1;
1497
1498 if (read_expected(EVENT_ITEM, "fmt") < 0)
1499 return -1;
1500
1501 if (read_expected(EVENT_OP, ":") < 0)
1502 return -1;
1503
1504 if (read_expect_type(EVENT_DQUOTE, &token) < 0)
1505 goto fail;
1506
1507 event->print_fmt.format = token;
1508 event->print_fmt.args = NULL;
1509
1510 /* ok to have no arg */
1511 type = read_token_item(&token);
1512
1513 if (type == EVENT_NONE)
1514 return 0;
1515
1516 if (test_type_token(type, token, EVENT_DELIM, ","))
1517 goto fail;
1518
1519 free_token(token);
1520
1521 ret = event_read_print_args(event, &event->print_fmt.args);
1522 if (ret < 0)
1523 return -1;
1524
1525 return 0;
1526
1527 fail:
1528 free_token(token);
1529 return -1;
1530}
1531
1532static struct format_field *
1533find_common_field(struct event *event, const char *name)
1534{
1535 struct format_field *format;
1536
1537 for (format = event->format.common_fields;
1538 format; format = format->next) {
1539 if (strcmp(format->name, name) == 0)
1540 break;
1541 }
1542
1543 return format;
1544}
1545
1546static struct format_field *
1547find_field(struct event *event, const char *name)
1548{
1549 struct format_field *format;
1550
1551 for (format = event->format.fields;
1552 format; format = format->next) {
1553 if (strcmp(format->name, name) == 0)
1554 break;
1555 }
1556
1557 return format;
1558}
1559
1560static struct format_field *
1561find_any_field(struct event *event, const char *name)
1562{
1563 struct format_field *format;
1564
1565 format = find_common_field(event, name);
1566 if (format)
1567 return format;
1568 return find_field(event, name);
1569}
1570
1571static unsigned long long read_size(void *ptr, int size)
1572{
1573 switch (size) {
1574 case 1:
1575 return *(unsigned char *)ptr;
1576 case 2:
1577 return *(unsigned short *)ptr;
1578 case 4:
1579 return *(unsigned int *)ptr;
1580 case 8:
1581 return *(unsigned long long *)ptr;
1582 default:
1583 /* BUG! */
1584 return 0;
1585 }
1586}
1587
1588static int get_common_info(const char *type, int *offset, int *size)
1589{
1590 struct event *event;
1591 struct format_field *field;
1592
1593 /*
1594 * All events should have the same common elements.
1595 * Pick any event to find where the type is;
1596 */
1597 if (!event_list)
1598 die("no event_list!");
1599
1600 event = event_list;
1601 field = find_common_field(event, type);
1602 if (!field)
1603 die("field '%s' not found", type);
1604
1605 *offset = field->offset;
1606 *size = field->size;
1607
1608 return 0;
1609}
1610
1611static int parse_common_type(void *data)
1612{
1613 static int type_offset;
1614 static int type_size;
1615 int ret;
1616
1617 if (!type_size) {
1618 ret = get_common_info("common_type",
1619 &type_offset,
1620 &type_size);
1621 if (ret < 0)
1622 return ret;
1623 }
1624 return read_size(data + type_offset, type_size);
1625}
1626
1627static int parse_common_pid(void *data)
1628{
1629 static int pid_offset;
1630 static int pid_size;
1631 int ret;
1632
1633 if (!pid_size) {
1634 ret = get_common_info("common_pid",
1635 &pid_offset,
1636 &pid_size);
1637 if (ret < 0)
1638 return ret;
1639 }
1640
1641 return read_size(data + pid_offset, pid_size);
1642}
1643
1644static struct event *find_event(int id)
1645{
1646 struct event *event;
1647
1648 for (event = event_list; event; event = event->next) {
1649 if (event->id == id)
1650 break;
1651 }
1652 return event;
1653}
1654
1655static unsigned long long eval_num_arg(void *data, int size,
1656 struct event *event, struct print_arg *arg)
1657{
1658 unsigned long long val = 0;
1659 unsigned long long left, right;
1660
1661 switch (arg->type) {
1662 case PRINT_NULL:
1663 /* ?? */
1664 return 0;
1665 case PRINT_ATOM:
1666 return strtoull(arg->atom.atom, NULL, 0);
1667 case PRINT_FIELD:
1668 if (!arg->field.field) {
1669 arg->field.field = find_any_field(event, arg->field.name);
1670 if (!arg->field.field)
1671 die("field %s not found", arg->field.name);
1672 }
1673 /* must be a number */
1674 val = read_size(data + arg->field.field->offset,
1675 arg->field.field->size);
1676 break;
1677 case PRINT_FLAGS:
1678 case PRINT_SYMBOL:
1679 break;
1680 case PRINT_TYPE:
1681 return eval_num_arg(data, size, event, arg->typecast.item);
1682 case PRINT_STRING:
1683 return 0;
1684 break;
1685 case PRINT_OP:
1686 left = eval_num_arg(data, size, event, arg->op.left);
1687 right = eval_num_arg(data, size, event, arg->op.right);
1688 switch (arg->op.op[0]) {
1689 case '|':
1690 if (arg->op.op[1])
1691 val = left || right;
1692 else
1693 val = left | right;
1694 break;
1695 case '&':
1696 if (arg->op.op[1])
1697 val = left && right;
1698 else
1699 val = left & right;
1700 break;
1701 case '<':
1702 switch (arg->op.op[1]) {
1703 case 0:
1704 val = left < right;
1705 break;
1706 case '<':
1707 val = left << right;
1708 break;
1709 case '=':
1710 val = left <= right;
1711 break;
1712 default:
1713 die("unknown op '%s'", arg->op.op);
1714 }
1715 break;
1716 case '>':
1717 switch (arg->op.op[1]) {
1718 case 0:
1719 val = left > right;
1720 break;
1721 case '>':
1722 val = left >> right;
1723 break;
1724 case '=':
1725 val = left >= right;
1726 break;
1727 default:
1728 die("unknown op '%s'", arg->op.op);
1729 }
1730 break;
1731 case '=':
1732 if (arg->op.op[1] != '=')
1733 die("unknown op '%s'", arg->op.op);
1734 val = left == right;
1735 break;
1736 }
1737 break;
1738 }
1739 return val;
1740}
1741
1742static unsigned long long eval_flag(const char *flag)
1743{
1744 /*
1745 * Some flags in the format files do not get converted.
1746 * If the flag is not numeric, see if it is something that
1747 * we already know about.
1748 */
1749 if (isdigit(flag[0]))
1750 return strtoull(flag, NULL, 0);
1751
1752 if (strcmp("HI_SOFTIRQ", flag) == 0)
1753 return 0;
1754 if (strcmp("TIMER_SOFTIRQ", flag) == 0)
1755 return 1;
1756 if (strcmp("NET_TX_SOFTIRQ", flag) == 0)
1757 return 2;
1758 if (strcmp("NET_RX_SOFTIRQ", flag) == 0)
1759 return 3;
1760 if (strcmp("BLOCK_SOFTIRQ", flag) == 0)
1761 return 4;
1762 if (strcmp("TASKLET_SOFTIRQ", flag) == 0)
1763 return 5;
1764 if (strcmp("SCHED_SOFTIRQ", flag) == 0)
1765 return 6;
1766 if (strcmp("HRTIMER_SOFTIRQ", flag) == 0)
1767 return 7;
1768 if (strcmp("RCU_SOFTIRQ", flag) == 0)
1769 return 8;
1770 return 0;
1771}
1772
1773static void print_str_arg(void *data, int size,
1774 struct event *event, struct print_arg *arg)
1775{
1776 struct print_flag_sym *flag;
1777 unsigned long long val, fval;
1778 char *str;
1779 int print;
1780
1781 switch (arg->type) {
1782 case PRINT_NULL:
1783 /* ?? */
1784 return;
1785 case PRINT_ATOM:
1786 return;
1787 case PRINT_FIELD:
1788 if (!arg->field.field) {
1789 arg->field.field = find_any_field(event, arg->field.name);
1790 if (!arg->field.field)
1791 die("field %s not found", arg->field.name);
1792 }
1793 str = malloc_or_die(arg->field.field->size + 1);
1794 memcpy(str, data + arg->field.field->offset,
1795 arg->field.field->size);
1796 str[arg->field.field->size] = 0;
1797 free(str);
1798 break;
1799 case PRINT_FLAGS:
1800 val = eval_num_arg(data, size, event, arg->flags.field);
1801 print = 0;
1802 for (flag = arg->flags.flags; flag; flag = flag->next) {
1803 fval = eval_flag(flag->value);
1804 if (!val && !fval) {
1805 printf("%s", flag->str);
1806 break;
1807 }
1808 if (fval && (val & fval) == fval) {
1809 if (print && arg->flags.delim)
1810 printf("%s", arg->flags.delim);
1811 printf("%s", flag->str);
1812 print = 1;
1813 val &= ~fval;
1814 }
1815 }
1816 break;
1817 case PRINT_SYMBOL:
1818 val = eval_num_arg(data, size, event, arg->symbol.field);
1819 for (flag = arg->symbol.symbols; flag; flag = flag->next) {
1820 fval = eval_flag(flag->value);
1821 if (val == fval) {
1822 printf("%s", flag->str);
1823 break;
1824 }
1825 }
1826 break;
1827
1828 case PRINT_TYPE:
1829 break;
1830 case PRINT_STRING:
1831 printf("%s", arg->string.string);
1832 break;
1833 case PRINT_OP:
1834 /*
1835 * The only op for string should be ? :
1836 */
1837 if (arg->op.op[0] != '?')
1838 return;
1839 val = eval_num_arg(data, size, event, arg->op.left);
1840 if (val)
1841 print_str_arg(data, size, event, arg->op.right->op.left);
1842 else
1843 print_str_arg(data, size, event, arg->op.right->op.right);
1844 break;
1845 }
1846}
1847
1848static void pretty_print(void *data, int size, struct event *event)
1849{
1850 struct print_fmt *print_fmt = &event->print_fmt;
1851 struct print_arg *arg = print_fmt->args;
1852 const char *ptr = print_fmt->format;
1853 unsigned long long val;
1854 struct func_map *func;
1855 const char *saveptr;
1856 char format[32];
1857 int show_func;
1858 int len;
1859 int ls;
1860
1861 if (event->flags & EVENT_FL_ISFUNC)
1862 ptr = " %pF <-- %pF";
1863
1864 for (; *ptr; ptr++) {
1865 ls = 0;
1866 if (*ptr == '%') {
1867 saveptr = ptr;
1868 show_func = 0;
1869 cont_process:
1870 ptr++;
1871 switch (*ptr) {
1872 case '%':
1873 printf("%%");
1874 break;
1875 case 'l':
1876 ls++;
1877 goto cont_process;
1878 case 'L':
1879 ls = 2;
1880 goto cont_process;
1881 case 'z':
1882 case 'Z':
1883 case '0' ... '9':
1884 goto cont_process;
1885 case 'p':
1886 if (long_size == 4)
1887 ls = 1;
1888 else
1889 ls = 2;
1890
1891 if (*(ptr+1) == 'F' ||
1892 *(ptr+1) == 'f') {
1893 ptr++;
1894 show_func = 1;
1895 }
1896
1897 /* fall through */
1898 case 'd':
1899 case 'i':
1900 case 'x':
1901 case 'X':
1902 case 'u':
1903 if (!arg)
1904 die("no argument match");
1905
1906 len = ((unsigned long)ptr + 1) -
1907 (unsigned long)saveptr;
1908
1909 /* should never happen */
1910 if (len > 32)
1911 die("bad format!");
1912
1913 memcpy(format, saveptr, len);
1914 format[len] = 0;
1915
1916 val = eval_num_arg(data, size, event, arg);
1917 arg = arg->next;
1918
1919 if (show_func) {
1920 func = find_func(val);
1921 if (func) {
1922 printf("%s+0x%llx",
1923 func->func,
1924 val - func->addr);
1925 break;
1926 }
1927 }
1928 switch (ls) {
1929 case 0:
1930 printf(format, (int)val);
1931 break;
1932 case 1:
1933 printf(format, (long)val);
1934 break;
1935 case 2:
1936 printf(format, (long long)val);
1937 break;
1938 default:
1939 die("bad count (%d)", ls);
1940 }
1941 break;
1942 case 's':
1943 if (!arg)
1944 die("no matching argument");
1945
1946 print_str_arg(data, size, event, arg);
1947 arg = arg->next;
1948 break;
1949 default:
1950 printf(">%c<", *ptr);
1951
1952 }
1953 } else
1954 printf("%c", *ptr);
1955 }
1956}
1957
1958static inline int log10_cpu(int nb)
1959{
1960 if (nb / 100)
1961 return 3;
1962 if (nb / 10)
1963 return 2;
1964 return 1;
1965}
1966
1967/* taken from Linux, written by Frederic Weisbecker */
1968static void print_graph_cpu(int cpu)
1969{
1970 int i;
1971 int log10_this = log10_cpu(cpu);
1972 int log10_all = log10_cpu(cpus);
1973
1974
1975 /*
1976 * Start with a space character - to make it stand out
1977 * to the right a bit when trace output is pasted into
1978 * email:
1979 */
1980 printf(" ");
1981
1982 /*
1983 * Tricky - we space the CPU field according to the max
1984 * number of online CPUs. On a 2-cpu system it would take
1985 * a maximum of 1 digit - on a 128 cpu system it would
1986 * take up to 3 digits:
1987 */
1988 for (i = 0; i < log10_all - log10_this; i++)
1989 printf(" ");
1990
1991 printf("%d) ", cpu);
1992}
1993
1994#define TRACE_GRAPH_PROCINFO_LENGTH 14
1995#define TRACE_GRAPH_INDENT 2
1996
1997static void print_graph_proc(int pid, const char *comm)
1998{
1999 /* sign + log10(MAX_INT) + '\0' */
2000 char pid_str[11];
2001 int spaces = 0;
2002 int len;
2003 int i;
2004
2005 sprintf(pid_str, "%d", pid);
2006
2007 /* 1 stands for the "-" character */
2008 len = strlen(comm) + strlen(pid_str) + 1;
2009
2010 if (len < TRACE_GRAPH_PROCINFO_LENGTH)
2011 spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
2012
2013 /* First spaces to align center */
2014 for (i = 0; i < spaces / 2; i++)
2015 printf(" ");
2016
2017 printf("%s-%s", comm, pid_str);
2018
2019 /* Last spaces to align center */
2020 for (i = 0; i < spaces - (spaces / 2); i++)
2021 printf(" ");
2022}
2023
2024static struct record *
2025get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2026 struct record *next)
2027{
2028 struct format_field *field;
2029 struct event *event;
2030 unsigned long val;
2031 int type;
2032 int pid;
2033
2034 type = parse_common_type(next->data);
2035 event = find_event(type);
2036 if (!event)
2037 return NULL;
2038
2039 if (!(event->flags & EVENT_FL_ISFUNCRET))
2040 return NULL;
2041
2042 pid = parse_common_pid(next->data);
2043 field = find_field(event, "func");
2044 if (!field)
2045 die("function return does not have field func");
2046
2047 val = read_size(next->data + field->offset, field->size);
2048
2049 if (cur_pid != pid || cur_func != val)
2050 return NULL;
2051
2052 /* this is a leaf, now advance the iterator */
2053 return read_data(cpu);
2054}
2055
2056/* Signal a overhead of time execution to the output */
2057static void print_graph_overhead(unsigned long long duration)
2058{
2059 /* Non nested entry or return */
2060 if (duration == -1)
2061 return (void)printf(" ");
2062
2063 /* Duration exceeded 100 msecs */
2064 if (duration > 100000ULL)
2065 return (void)printf("! ");
2066
2067 /* Duration exceeded 10 msecs */
2068 if (duration > 10000ULL)
2069 return (void)printf("+ ");
2070
2071 printf(" ");
2072}
2073
2074static void print_graph_duration(unsigned long long duration)
2075{
2076 unsigned long usecs = duration / 1000;
2077 unsigned long nsecs_rem = duration % 1000;
2078 /* log10(ULONG_MAX) + '\0' */
2079 char msecs_str[21];
2080 char nsecs_str[5];
2081 int len;
2082 int i;
2083
2084 sprintf(msecs_str, "%lu", usecs);
2085
2086 /* Print msecs */
2087 len = printf("%lu", usecs);
2088
2089 /* Print nsecs (we don't want to exceed 7 numbers) */
2090 if (len < 7) {
2091 snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
2092 len += printf(".%s", nsecs_str);
2093 }
2094
2095 printf(" us ");
2096
2097 /* Print remaining spaces to fit the row's width */
2098 for (i = len; i < 7; i++)
2099 printf(" ");
2100
2101 printf("| ");
2102}
2103
2104static void
2105print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec)
2106{
2107 unsigned long long rettime, calltime;
2108 unsigned long long duration, depth;
2109 unsigned long long val;
2110 struct format_field *field;
2111 struct func_map *func;
2112 struct event *ret_event;
2113 int type;
2114 int i;
2115
2116 type = parse_common_type(ret_rec->data);
2117 ret_event = find_event(type);
2118
2119 field = find_field(ret_event, "rettime");
2120 if (!field)
2121 die("can't find rettime in return graph");
2122 rettime = read_size(ret_rec->data + field->offset, field->size);
2123
2124 field = find_field(ret_event, "calltime");
2125 if (!field)
2126 die("can't find rettime in return graph");
2127 calltime = read_size(ret_rec->data + field->offset, field->size);
2128
2129 duration = rettime - calltime;
2130
2131 /* Overhead */
2132 print_graph_overhead(duration);
2133
2134 /* Duration */
2135 print_graph_duration(duration);
2136
2137 field = find_field(event, "depth");
2138 if (!field)
2139 die("can't find depth in entry graph");
2140 depth = read_size(data + field->offset, field->size);
2141
2142 /* Function */
2143 for (i = 0; i < depth * TRACE_GRAPH_INDENT; i++)
2144 printf(" ");
2145
2146 field = find_field(event, "func");
2147 if (!field)
2148 die("can't find func in entry graph");
2149 val = read_size(data + field->offset, field->size);
2150 func = find_func(val);
2151
2152 if (func)
2153 printf("%s();", func->func);
2154 else
2155 printf("%llx();", val);
2156}
2157
2158static void print_graph_nested(struct event *event, void *data)
2159{
2160 struct format_field *field;
2161 unsigned long long depth;
2162 unsigned long long val;
2163 struct func_map *func;
2164 int i;
2165
2166 /* No overhead */
2167 print_graph_overhead(-1);
2168
2169 /* No time */
2170 printf(" | ");
2171
2172 field = find_field(event, "depth");
2173 if (!field)
2174 die("can't find depth in entry graph");
2175 depth = read_size(data + field->offset, field->size);
2176
2177 /* Function */
2178 for (i = 0; i < depth * TRACE_GRAPH_INDENT; i++)
2179 printf(" ");
2180
2181 field = find_field(event, "func");
2182 if (!field)
2183 die("can't find func in entry graph");
2184 val = read_size(data + field->offset, field->size);
2185 func = find_func(val);
2186
2187 if (func)
2188 printf("%s() {", func->func);
2189 else
2190 printf("%llx() {", val);
2191}
2192
2193static void
2194pretty_print_func_ent(void *data, int size, struct event *event,
2195 int cpu, int pid, const char *comm,
2196 unsigned long secs, unsigned long usecs)
2197{
2198 struct format_field *field;
2199 struct record *rec;
2200 void *copy_data;
2201 unsigned long val;
2202
2203 printf("%5lu.%06lu | ", secs, usecs);
2204
2205 print_graph_cpu(cpu);
2206 print_graph_proc(pid, comm);
2207
2208 printf(" | ");
2209
2210 field = find_field(event, "func");
2211 if (!field)
2212 die("function entry does not have func field");
2213
2214 val = read_size(data + field->offset, field->size);
2215
2216 /*
2217 * peak_data may unmap the data pointer. Copy it first.
2218 */
2219 copy_data = malloc_or_die(size);
2220 memcpy(copy_data, data, size);
2221 data = copy_data;
2222
2223 rec = peak_data(cpu);
2224 if (rec) {
2225 rec = get_return_for_leaf(cpu, pid, val, rec);
2226 if (rec) {
2227 print_graph_entry_leaf(event, data, rec);
2228 goto out_free;
2229 }
2230 }
2231 print_graph_nested(event, data);
2232out_free:
2233 free(data);
2234}
2235
2236static void
2237pretty_print_func_ret(void *data, int size, struct event *event,
2238 int cpu, int pid, const char *comm,
2239 unsigned long secs, unsigned long usecs)
2240{
2241 unsigned long long rettime, calltime;
2242 unsigned long long duration, depth;
2243 struct format_field *field;
2244 int i;
2245
2246 printf("%5lu.%06lu | ", secs, usecs);
2247
2248 print_graph_cpu(cpu);
2249 print_graph_proc(pid, comm);
2250
2251 printf(" | ");
2252
2253 field = find_field(event, "rettime");
2254 if (!field)
2255 die("can't find rettime in return graph");
2256 rettime = read_size(data + field->offset, field->size);
2257
2258 field = find_field(event, "calltime");
2259 if (!field)
2260 die("can't find calltime in return graph");
2261 calltime = read_size(data + field->offset, field->size);
2262
2263 duration = rettime - calltime;
2264
2265 /* Overhead */
2266 print_graph_overhead(duration);
2267
2268 /* Duration */
2269 print_graph_duration(duration);
2270
2271 field = find_field(event, "depth");
2272 if (!field)
2273 die("can't find depth in entry graph");
2274 depth = read_size(data + field->offset, field->size);
2275
2276 /* Function */
2277 for (i = 0; i < depth * TRACE_GRAPH_INDENT; i++)
2278 printf(" ");
2279
2280 printf("}");
2281}
2282
2283static void
2284pretty_print_func_graph(void *data, int size, struct event *event,
2285 int cpu, int pid, const char *comm,
2286 unsigned long secs, unsigned long usecs)
2287{
2288 if (event->flags & EVENT_FL_ISFUNCENT)
2289 pretty_print_func_ent(data, size, event,
2290 cpu, pid, comm, secs, usecs);
2291 else if (event->flags & EVENT_FL_ISFUNCRET)
2292 pretty_print_func_ret(data, size, event,
2293 cpu, pid, comm, secs, usecs);
2294 printf("\n");
2295}
2296
2297void print_event(int cpu, void *data, int size, unsigned long long nsecs)
2298{
2299 struct event *event;
2300 unsigned long secs;
2301 unsigned long usecs;
2302 const char *comm;
2303 int type;
2304 int pid;
2305
2306 secs = nsecs / NSECS_PER_SEC;
2307 nsecs -= secs * NSECS_PER_SEC;
2308 usecs = nsecs / NSECS_PER_USEC;
2309
2310 type = parse_common_type(data);
2311
2312 event = find_event(type);
2313 if (!event)
2314 die("ug! no event found");
2315
2316 pid = parse_common_pid(data);
2317 comm = find_cmdline(pid);
2318
2319 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
2320 return pretty_print_func_graph(data, size, event, cpu,
2321 pid, comm, secs, usecs);
2322
2323 printf("%16s-%-5d [%03d] %5lu.%06lu: %s: ",
2324 comm, pid, cpu,
2325 secs, usecs, event->name);
2326
2327 pretty_print(data, size, event);
2328 printf("\n");
2329}
2330
2331void print_fields(struct print_flag_sym *field)
2332{
2333 printf("{ %s, %s }", field->value, field->str);
2334 if (field->next) {
2335 printf(", ");
2336 print_fields(field->next);
2337 }
2338}
2339
2340void print_args(struct print_arg *args)
2341{
2342 int print_paren = 1;
2343
2344 switch (args->type) {
2345 case PRINT_NULL:
2346 printf("null");
2347 break;
2348 case PRINT_ATOM:
2349 printf("%s", args->atom.atom);
2350 break;
2351 case PRINT_FIELD:
2352 printf("REC->%s", args->field.name);
2353 break;
2354 case PRINT_FLAGS:
2355 printf("__print_flags(");
2356 print_args(args->flags.field);
2357 printf(", %s, ", args->flags.delim);
2358 print_fields(args->flags.flags);
2359 printf(")");
2360 break;
2361 case PRINT_SYMBOL:
2362 printf("__print_symbolic(");
2363 print_args(args->symbol.field);
2364 printf(", ");
2365 print_fields(args->symbol.symbols);
2366 printf(")");
2367 break;
2368 case PRINT_STRING:
2369 printf("__get_str(%s)", args->string.string);
2370 break;
2371 case PRINT_TYPE:
2372 printf("(%s)", args->typecast.type);
2373 print_args(args->typecast.item);
2374 break;
2375 case PRINT_OP:
2376 if (strcmp(args->op.op, ":") == 0)
2377 print_paren = 0;
2378 if (print_paren)
2379 printf("(");
2380 print_args(args->op.left);
2381 printf(" %s ", args->op.op);
2382 print_args(args->op.right);
2383 if (print_paren)
2384 printf(")");
2385 break;
2386 }
2387 if (args->next) {
2388 printf("\n");
2389 print_args(args->next);
2390 }
2391}
2392
2393int parse_ftrace_file(char *buf, unsigned long size)
2394{
2395 struct format_field *field;
2396 struct print_arg *arg, **list;
2397 struct event *event;
2398 int ret;
2399
2400 init_input_buf(buf, size);
2401
2402 event = alloc_event();
2403 if (!event)
2404 return -ENOMEM;
2405
2406 event->flags |= EVENT_FL_ISFTRACE;
2407
2408 event->name = event_read_name();
2409 if (!event->name)
2410 die("failed to read ftrace event name");
2411
2412 if (strcmp(event->name, "function") == 0)
2413 event->flags |= EVENT_FL_ISFUNC;
2414
2415 else if (strcmp(event->name, "funcgraph_entry") == 0)
2416 event->flags |= EVENT_FL_ISFUNCENT;
2417
2418 else if (strcmp(event->name, "funcgraph_exit") == 0)
2419 event->flags |= EVENT_FL_ISFUNCRET;
2420
2421 event->id = event_read_id();
2422 if (event->id < 0)
2423 die("failed to read ftrace event id");
2424
2425 add_event(event);
2426
2427 ret = event_read_format(event);
2428 if (ret < 0)
2429 die("failed to read ftrace event format");
2430
2431 ret = event_read_print(event);
2432 if (ret < 0)
2433 die("failed to read ftrace event print fmt");
2434
2435 /*
2436 * The arguments for ftrace files are parsed by the fields.
2437 * Set up the fields as their arguments.
2438 */
2439 list = &event->print_fmt.args;
2440 for (field = event->format.fields; field; field = field->next) {
2441 arg = malloc_or_die(sizeof(*arg));
2442 memset(arg, 0, sizeof(*arg));
2443 *list = arg;
2444 list = &arg->next;
2445 arg->type = PRINT_FIELD;
2446 arg->field.name = field->name;
2447 arg->field.field = field;
2448 }
2449 return 0;
2450}
2451
2452int parse_event_file(char *buf, unsigned long size, char *system)
2453{
2454 struct event *event;
2455 int ret;
2456
2457 init_input_buf(buf, size);
2458
2459 event = alloc_event();
2460 if (!event)
2461 return -ENOMEM;
2462
2463 event->name = event_read_name();
2464 if (!event->name)
2465 die("failed to read event name");
2466
2467 event->id = event_read_id();
2468 if (event->id < 0)
2469 die("failed to read event id");
2470
2471 ret = event_read_format(event);
2472 if (ret < 0)
2473 die("failed to read event format");
2474
2475 ret = event_read_print(event);
2476 if (ret < 0)
2477 die("failed to read event print fmt");
2478
2479#define PRINT_ARGS 0
2480 if (PRINT_ARGS && event->print_fmt.args)
2481 print_args(event->print_fmt.args);
2482
2483 add_event(event);
2484 return 0;
2485}
2486
2487void parse_set_info(int nr_cpus, int long_sz)
2488{
2489 cpus = nr_cpus;
2490 long_size = long_sz;
2491}
diff --git a/parse-events.h b/parse-events.h
new file mode 100644
index 0000000..e77af1f
--- /dev/null
+++ b/parse-events.h
@@ -0,0 +1,171 @@
1#ifndef _PARSE_EVENTS_H
2#define _PARSE_EVENTS_H
3
4#ifndef PAGE_SIZE
5#define PAGE_SIZE 4096ULL
6#endif
7
8#ifndef PAGE_MASK
9#define PAGE_MASK (PAGE_SIZE - 1)
10#endif
11
12enum {
13 RINGBUF_TYPE_PADDING = 29,
14 RINGBUF_TYPE_TIME_EXTEND = 30,
15 RINGBUF_TYPE_TIME_STAMP = 31,
16};
17
18#ifndef TS_SHIFT
19#define TS_SHIFT 27
20#endif
21
22#define NSECS_PER_SEC 1000000000ULL
23#define NSECS_PER_USEC 1000ULL
24
25enum format_flags {
26 FIELD_IS_ARRAY = 1,
27 FIELD_IS_POINTER = 2,
28};
29
30struct format_field {
31 struct format_field *next;
32 char *type;
33 char *name;
34 int offset;
35 int size;
36 unsigned long flags;
37};
38
39struct format {
40 int nr_common;
41 int nr_fields;
42 struct format_field *common_fields;
43 struct format_field *fields;
44};
45
46struct print_arg_atom {
47 char *atom;
48};
49
50struct print_arg_string {
51 char *string;
52};
53
54struct print_arg_field {
55 char *name;
56 struct format_field *field;
57};
58
59struct print_flag_sym {
60 struct print_flag_sym *next;
61 char *value;
62 char *str;
63};
64
65struct print_arg_typecast {
66 char *type;
67 struct print_arg *item;
68};
69
70struct print_arg_flags {
71 struct print_arg *field;
72 char *delim;
73 struct print_flag_sym *flags;
74};
75
76struct print_arg_symbol {
77 struct print_arg *field;
78 struct print_flag_sym *symbols;
79};
80
81struct print_arg;
82
83struct print_arg_op {
84 char *op;
85 int prio;
86 struct print_arg *left;
87 struct print_arg *right;
88};
89
90struct print_arg_func {
91 char *name;
92 struct print_arg *args;
93};
94
95enum print_arg_type {
96 PRINT_NULL,
97 PRINT_ATOM,
98 PRINT_FIELD,
99 PRINT_FLAGS,
100 PRINT_SYMBOL,
101 PRINT_TYPE,
102 PRINT_STRING,
103 PRINT_OP,
104};
105
106struct print_arg {
107 struct print_arg *next;
108 enum print_arg_type type;
109 union {
110 struct print_arg_atom atom;
111 struct print_arg_field field;
112 struct print_arg_typecast typecast;
113 struct print_arg_flags flags;
114 struct print_arg_symbol symbol;
115 struct print_arg_func func;
116 struct print_arg_string string;
117 struct print_arg_op op;
118 };
119};
120
121struct print_fmt {
122 char *format;
123 struct print_arg *args;
124};
125
126struct event {
127 struct event *next;
128 char *name;
129 int id;
130 int flags;
131 struct format format;
132 struct print_fmt print_fmt;
133};
134
135enum {
136 EVENT_FL_ISFTRACE = 1,
137 EVENT_FL_ISPRINT = 2,
138 EVENT_FL_ISBPRINT = 4,
139 EVENT_FL_ISFUNC = 8,
140 EVENT_FL_ISFUNCENT = 16,
141 EVENT_FL_ISFUNCRET = 32,
142};
143
144struct record {
145 unsigned long long ts;
146 int size;
147 void *data;
148};
149
150void usage(char **argv);
151
152struct record *peak_data(int cpu);
153struct record *read_data(int cpu);
154
155void parse_set_info(int nr_cpus, int long_sz);
156
157void trace_report(int argc, char **argv);
158
159void die(char *fmt, ...);
160void *malloc_or_die(unsigned int size);
161
162void parse_cmdlines(char *file, int size);
163void parse_proc_kallsyms(char *file, unsigned int size);
164
165void print_funcs(void);
166
167int parse_ftrace_file(char *buf, unsigned long size);
168int parse_event_file(char *buf, unsigned long size, char *system);
169void print_event(int cpu, void *data, int size, unsigned long long nsecs);
170
171#endif /* _PARSE_EVENTS_H */
diff --git a/trace-cmd.c b/trace-cmd.c
new file mode 100644
index 0000000..72f070b
--- /dev/null
+++ b/trace-cmd.c
@@ -0,0 +1,1143 @@
1/*
2 * Copyright (C) 2008,2009, Steven Rostedt <srostedt@redhat.com>
3 *
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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; version 2 of the License (not later!)
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 */
21#define _GNU_SOURCE
22#include <dirent.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stdarg.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/wait.h>
30#include <pthread.h>
31#include <fcntl.h>
32#include <unistd.h>
33#include <ctype.h>
34#include <errno.h>
35
36#include "parse-events.h"
37
38
39#define VERSION "0.5"
40
41#define _STR(x) #x
42#define STR(x) _STR(x)
43#define MAX_PATH 256
44
45#define TRACE_CTRL "tracing_on"
46#define TRACE "trace"
47#define AVAILABLE "available_tracers"
48#define CURRENT "current_tracer"
49#define ITER_CTRL "trace_options"
50#define MAX_LATENCY "tracing_max_latency"
51
52static const char *output_file = "trace.dat";
53static int output_fd;
54
55static int latency;
56
57static int old_ftrace_name;
58
59static int cpu_count;
60static int *pids;
61
62struct event_list {
63 struct event_list *next;
64 const char *event;
65};
66
67static struct event_list *event_selection;
68
69struct events {
70 struct events *sibling;
71 struct events *children;
72 struct events *next;
73 char *name;
74};
75
76static void delete_temp_file(int cpu)
77{
78 char file[MAX_PATH];
79
80 snprintf(file, MAX_PATH, "%s.cpu%d", output_file, cpu);
81 unlink(file);
82}
83
84static void kill_threads(void)
85{
86 int i;
87
88 if (!cpu_count)
89 return;
90
91 for (i = 0; i < cpu_count; i++) {
92 if (pids[i]) {
93 kill(pids[i], SIGKILL);
94 delete_temp_file(i);
95 }
96 }
97}
98
99static void delete_thread_data(void)
100{
101 int i;
102
103 if (!cpu_count)
104 return;
105
106 for (i = 0; i < cpu_count; i++) {
107 if (pids[i])
108 delete_temp_file(i);
109 }
110}
111
112static void stop_threads(void)
113{
114 int i;
115
116 if (!cpu_count)
117 return;
118
119 for (i = 0; i < cpu_count; i++) {
120 if (pids[i]) {
121 kill(pids[i], SIGINT);
122 waitpid(pids[i], NULL, 0);
123 pids[i] = 0;
124 }
125 }
126}
127
128void die(char *fmt, ...)
129{
130 va_list ap;
131 int ret = errno;
132
133 if (errno)
134 perror("trace-cmd");
135 else
136 ret = -1;
137
138 kill_threads();
139 va_start(ap, fmt);
140 fprintf(stderr, " ");
141 vfprintf(stderr, fmt, ap);
142 va_end(ap);
143
144 fprintf(stderr, "\n");
145 exit(ret);
146}
147
148void *malloc_or_die(unsigned int size)
149{
150 void *data;
151
152 data = malloc(size);
153 if (!data)
154 die("malloc");
155 return data;
156}
157
158static const char *find_debugfs(void)
159{
160 static char debugfs[MAX_PATH+1];
161 static int debugfs_found;
162 char type[100];
163 FILE *fp;
164
165 if (debugfs_found)
166 return debugfs;
167
168 if ((fp = fopen("/proc/mounts","r")) == NULL)
169 die("Can't open /proc/mounts for read");
170
171 while (fscanf(fp, "%*s %"
172 STR(MAX_PATH)
173 "s %99s %*s %*d %*d\n",
174 debugfs, type) == 2) {
175 if (strcmp(type, "debugfs") == 0)
176 break;
177 }
178 fclose(fp);
179
180 if (strcmp(type, "debugfs") != 0)
181 die("debugfs not mounted, please mount");
182
183 debugfs_found = 1;
184
185 return debugfs;
186}
187
188/*
189 * Finds the path to the debugfs/tracing
190 * Allocates the string and stores it.
191 */
192static const char *find_tracing_dir(void)
193{
194 static char *tracing;
195 static int tracing_found;
196 const char *debugfs;
197
198 if (tracing_found)
199 return tracing;
200
201 debugfs = find_debugfs();
202
203 tracing = malloc_or_die(strlen(debugfs) + 9);
204
205 sprintf(tracing, "%s/tracing", debugfs);
206
207 tracing_found = 1;
208 return tracing;
209}
210
211static char *get_tracing_file(const char *name)
212{
213 const char *tracing;
214 char *file;
215
216 tracing = find_tracing_dir();
217 if (!tracing)
218 return NULL;
219
220 file = malloc_or_die(strlen(tracing) + strlen(name) + 2);
221
222 sprintf(file, "%s/%s", tracing, name);
223 return file;
224}
225
226static void put_tracing_file(char *file)
227{
228 if (file)
229 free(file);
230}
231
232static void write_trace(const char *file, const char *val)
233{
234 char *path;
235 int fd;
236
237 path = get_tracing_file(file);
238 fd = open(path, O_WRONLY);
239 if (fd < 0)
240 die("writing %s", path);
241 put_tracing_file(path);
242 write(fd, val, strlen(val));
243 close(fd);
244
245}
246
247static int find_trace_type(const char *type)
248{
249 char scan[100];
250 char *path;
251 FILE *fp;
252 int ret;
253
254 path = get_tracing_file(path);
255 fp = fopen(path, "r");
256 if (!fp)
257 die("reading %s", path);
258 put_tracing_file(path);
259 do {
260 ret = fscanf(fp, "%99s", scan);
261 if (ret > 0 && strcmp(scan, "ftrace"))
262 old_ftrace_name = 1;
263 if (ret > 0 && strcmp(scan, type) == 0)
264 break;
265 } while (ret > 0);
266 fclose(fp);
267
268 return ret > 0;
269}
270
271static void set_ftrace(int set)
272{
273 int fd;
274 char *val = set ? "1" : "0";
275
276 fd = open("/proc/sys/kernel/ftrace_enabled", O_WRONLY);
277 if (fd < 0)
278 die ("Can't %s ftrace", set ? "enable" : "disable");
279
280 write(fd, val, 1);
281 close(fd);
282}
283
284void run_cmd(int argc, char **argv)
285{
286 int status;
287 int pid;
288
289 if ((pid = fork()) < 0)
290 die("failed to fork");
291 if (!pid) {
292 /* child */
293 if (execvp(argv[0], argv))
294 exit(-1);
295 }
296 waitpid(pid, &status, 0);
297}
298
299static void show_events(void)
300{
301 char buf[BUFSIZ];
302 char *path;
303 FILE *fp;
304 size_t n;
305
306 path = get_tracing_file("available_events");
307 fp = fopen(path, "r");
308 if (!fp)
309 die("reading %s", path);
310 put_tracing_file(path);
311
312 do {
313 n = fread(buf, 1, BUFSIZ, fp);
314 if (n > 0)
315 fwrite(buf, 1, n, stdout);
316 } while (n > 0);
317 fclose(fp);
318}
319
320static void show_plugins(void)
321{
322 char buf[BUFSIZ];
323 char *path;
324 FILE *fp;
325 size_t n;
326
327 path = get_tracing_file("available_tracers");
328 fp = fopen(path, "r");
329 if (!fp)
330 die("reading %s", path);
331 put_tracing_file(path);
332
333 do {
334 n = fread(buf, 1, BUFSIZ, fp);
335 if (n > 0)
336 fwrite(buf, 1, n, stdout);
337 } while (n > 0);
338 fclose(fp);
339}
340
341static void set_plugin(const char *name)
342{
343 FILE *fp;
344 char *path;
345
346 path = get_tracing_file("current_tracer");
347 fp = fopen(path, "w");
348 if (!fp)
349 die("writing to '%s'", path);
350 put_tracing_file(path);
351
352 fwrite(name, 1, strlen(name), fp);
353 fclose(fp);
354}
355
356static void enable_event(const char *name)
357{
358 FILE *fp;
359 char *path;
360 int ret;
361
362 printf("enable %s\n", name);
363 if (strcmp(name, "all") == 0) {
364 path = get_tracing_file("events/enable");
365 fp = fopen(path, "w");
366 if (!fp)
367 die("writing to '%s'", path);
368 put_tracing_file(path);
369 ret = fwrite("1", 1, 1, fp);
370 fclose(fp);
371 if (ret < 0)
372 die("writing to '%s'", path);
373 return;
374 }
375
376 path = get_tracing_file("set_event");
377 fp = fopen(path, "w");
378 if (!fp)
379 die("writing to '%s'", path);
380 put_tracing_file(path);
381 ret = fwrite(name, 1, strlen(name), fp);
382 if (ret < 0)
383 die("bad event '%s'", name);
384 ret = fwrite("\n", 1, 1, fp);
385 if (ret < 0)
386 die("bad event '%s'", name);
387 fclose(fp);
388}
389
390static void disable_event(const char *name)
391{
392 FILE *fp;
393 char *path;
394
395 if (strcmp(name, "all") == 0) {
396 path = get_tracing_file("events/enable");
397 fp = fopen(path, "w");
398 if (!fp)
399 die("writing to '%s'", path);
400 put_tracing_file(path);
401 fwrite("0", 1, 1, fp);
402 fclose(fp);
403 }
404}
405
406static void enable_tracing(void)
407{
408 FILE *fp;
409 char *path;
410
411 /* reset the trace */
412 path = get_tracing_file("tracing_on");
413 fp = fopen(path, "w");
414 if (!fp)
415 die("writing to '%s'", path);
416 put_tracing_file(path);
417 fwrite("1", 1, 1, fp);
418 fclose(fp);
419}
420
421static void disable_tracing(void)
422{
423 FILE *fp;
424 char *path;
425
426 /* reset the trace */
427 path = get_tracing_file("tracing_on");
428 fp = fopen(path, "w");
429 if (!fp)
430 die("writing to '%s'", path);
431 put_tracing_file(path);
432 fwrite("0", 1, 1, fp);
433 fclose(fp);
434}
435
436static void disable_all(void)
437{
438 FILE *fp;
439 char *path;
440
441 disable_tracing();
442
443 set_plugin("nop");
444 disable_event("all");
445
446 /* reset the trace */
447 path = get_tracing_file("trace");
448 fp = fopen(path, "w");
449 if (!fp)
450 die("writing to '%s'", path);
451 put_tracing_file(path);
452 fwrite("0", 1, 1, fp);
453 fclose(fp);
454}
455
456static void enable_events(void)
457{
458 struct event_list *event;
459
460 for (event = event_selection; event; event = event->next) {
461 enable_event(event->event);
462 }
463}
464
465static int count_cpus(void)
466{
467 FILE *fp;
468 char buf[1024];
469 int cpus = 0;
470 char *pbuf;
471 size_t *pn;
472 size_t n;
473 int r;
474
475 n = 1024;
476 pn = &n;
477 pbuf = buf;
478
479 fp = fopen("/proc/cpuinfo", "r");
480 if (!fp)
481 die("Can not read cpuinfo");
482
483 while ((r = getline(&pbuf, pn, fp)) >= 0) {
484 char *p;
485
486 if (strncmp(buf, "processor", 9) != 0)
487 continue;
488 for (p = buf+9; isspace(*p); p++)
489 ;
490 if (*p == ':')
491 cpus++;
492 }
493 fclose(fp);
494
495 return cpus;
496}
497
498static int finished;
499
500static void finish(int sig)
501{
502 /* all done */
503 finished = 1;
504}
505
506static int create_recorder(int cpu)
507{
508 char file[MAX_PATH];
509 const char *tracing;
510 char *path;
511 int out_fd;
512 int in_fd;
513 int brass[2];
514 int pid;
515 int ret;
516 char buf[PAGE_SIZE];
517
518 pid = fork();
519 if (pid < 0)
520 die("fork");
521
522 if (pid)
523 return pid;
524
525 signal(SIGINT, finish);
526
527 /* do not kill tasks on error */
528 cpu_count = 0;
529
530 snprintf(file, MAX_PATH, "%s.cpu%d", output_file, cpu);
531
532 out_fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
533 if (out_fd < 0)
534 die("can't create file '%s'", file);
535
536 tracing = find_tracing_dir();
537
538 path = malloc_or_die(strlen(tracing) + 40);
539
540 sprintf(path, "%s/per_cpu/cpu%d/trace_pipe_raw", tracing, cpu);
541 in_fd = open(path, O_RDONLY);
542 if (in_fd < 0)
543 die("can not read '%s'", path);
544
545 ret = pipe(brass);
546 if (ret < 0)
547 die("can not create pipe");
548
549 do {
550 ret = splice(in_fd, NULL, brass[1], NULL, PAGE_SIZE, 1 /* SPLICE_F_MOVE */);
551 if (ret < 0) {
552 perror("in");
553 printf("errno=%d\n", errno);
554 die("splice in");
555 }
556 ret = splice(brass[0], NULL, out_fd, NULL, PAGE_SIZE, 3 /* and NON_BLOCK */);
557 if (ret < 0 && errno != EAGAIN) {
558 perror("in");
559 printf("errno=%d\n", errno);
560 die("splice out");
561 }
562 } while (!finished);
563
564 /* splice only reads full pages */
565 do {
566 ret = read(in_fd, buf, PAGE_SIZE);
567 if (ret > 0)
568 write(out_fd, buf, ret);
569 } while (ret > 0);
570
571 exit(0);
572}
573
574static void start_threads(void)
575{
576 int cpus;
577 int i;
578
579 cpus = count_cpus();
580
581 /* make a thread for every CPU we have */
582 pids = malloc_or_die(sizeof(*pids) * cpu_count);
583
584 memset(pids, 0, sizeof(*pids) * cpu_count);
585
586 cpu_count = cpus;
587
588 for (i = 0; i < cpus; i++) {
589 pids[i] = create_recorder(i);
590 }
591}
592
593static ssize_t write_or_die(const void *buf, size_t len)
594{
595 int ret;
596
597 ret = write(output_fd, buf, len);
598 if (ret < 0)
599 die("writing to '%s'", output_file);
600
601 return ret;
602}
603
604static int bigendian(void)
605{
606 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
607 unsigned int *ptr;
608
609 ptr = (unsigned int *)str;
610 return *ptr == 0x1234;
611}
612
613static unsigned long long copy_file_fd(int fd)
614{
615 unsigned long long size = 0;
616 char buf[BUFSIZ];
617 int r;
618
619 do {
620 r = read(fd, buf, BUFSIZ);
621 if (r > 0) {
622 size += r;
623 write_or_die(buf, r);
624 }
625 } while (r > 0);
626
627 return size;
628}
629
630static unsigned long long copy_file(const char *file)
631{
632 unsigned long long size = 0;
633 int fd;
634
635 fd = open(file, O_RDONLY);
636 if (fd < 0)
637 die("Can't read '%s'", file);
638 size = copy_file_fd(fd);
639 close(fd);
640
641 return size;
642}
643
644static unsigned long get_size_fd(int fd)
645{
646 unsigned long long size = 0;
647 char buf[BUFSIZ];
648 int r;
649
650 do {
651 r = read(fd, buf, BUFSIZ);
652 if (r > 0)
653 size += r;
654 } while (r > 0);
655
656 lseek(fd, 0, SEEK_SET);
657
658 return size;
659}
660
661static unsigned long get_size(const char *file)
662{
663 unsigned long long size = 0;
664 int fd;
665
666 fd = open(file, O_RDONLY);
667 if (fd < 0)
668 die("Can't read '%s'", file);
669 size = get_size_fd(fd);
670 close(fd);
671
672 return size;
673}
674
675static void read_header_files(void)
676{
677 unsigned long long size, check_size;
678 char *path;
679 int fd;
680
681 path = get_tracing_file("events/header_page");
682 fd = open(path, O_RDONLY);
683 if (fd < 0)
684 die("can't read '%s'", path);
685
686 /* unfortunately, you can not stat debugfs files for size */
687 size = get_size_fd(fd);
688
689 write_or_die("header_page", 12);
690 write_or_die(&size, 8);
691 check_size = copy_file_fd(fd);
692 if (size != check_size)
693 die("wrong size for '%s' size=%lld read=%lld",
694 path, size, check_size);
695 put_tracing_file(path);
696
697 path = get_tracing_file("events/header_event");
698 fd = open(path, O_RDONLY);
699 if (fd < 0)
700 die("can't read '%s'", path);
701
702 size = get_size_fd(fd);
703
704 write_or_die("header_event", 13);
705 write_or_die(&size, 8);
706 check_size = copy_file_fd(fd);
707 if (size != check_size)
708 die("wrong size for '%s'", path);
709 put_tracing_file(path);
710}
711
712static void copy_event_system(const char *sys)
713{
714 unsigned long long size, check_size;
715 struct dirent *dent;
716 struct stat st;
717 char *format;
718 DIR *dir;
719 int count = 0;
720 int ret;
721
722 dir = opendir(sys);
723 if (!dir)
724 die("can't read directory '%s'", sys);
725
726 while ((dent = readdir(dir))) {
727 if (strcmp(dent->d_name, ".") == 0 ||
728 strcmp(dent->d_name, "..") == 0)
729 continue;
730 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
731 sprintf(format, "%s/%s/format", sys, dent->d_name);
732 ret = stat(format, &st);
733 free(format);
734 if (ret < 0)
735 continue;
736 count++;
737 }
738
739 write_or_die(&count, 4);
740
741 rewinddir(dir);
742 while ((dent = readdir(dir))) {
743 if (strcmp(dent->d_name, ".") == 0 ||
744 strcmp(dent->d_name, "..") == 0)
745 continue;
746 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10);
747 sprintf(format, "%s/%s/format", sys, dent->d_name);
748 ret = stat(format, &st);
749
750 if (ret >= 0) {
751 /* unfortunately, you can not stat debugfs files for size */
752 size = get_size(format);
753 write_or_die(&size, 8);
754 check_size = copy_file(format);
755 if (size != check_size)
756 die("error in size of file '%s'", format);
757 }
758
759 free(format);
760 }
761}
762
763static void read_ftrace_files(void)
764{
765 char *path;
766
767 path = get_tracing_file("events/ftrace");
768
769 copy_event_system(path);
770
771 put_tracing_file(path);
772}
773
774static void read_event_files(void)
775{
776 struct dirent *dent;
777 struct stat st;
778 char *path;
779 char *sys;
780 DIR *dir;
781 int count = 0;
782 int ret;
783
784 path = get_tracing_file("events");
785
786 dir = opendir(path);
787 if (!dir)
788 die("can't read directory '%s'", path);
789
790 while ((dent = readdir(dir))) {
791 if (strcmp(dent->d_name, ".") == 0 ||
792 strcmp(dent->d_name, "..") == 0 ||
793 strcmp(dent->d_name, "ftrace") == 0)
794 continue;
795 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
796 sprintf(sys, "%s/%s", path, dent->d_name);
797 ret = stat(sys, &st);
798 free(sys);
799 if (ret < 0)
800 continue;
801 if (S_ISDIR(st.st_mode))
802 count++;
803 }
804
805 write_or_die(&count, 4);
806
807 rewinddir(dir);
808 while ((dent = readdir(dir))) {
809 if (strcmp(dent->d_name, ".") == 0 ||
810 strcmp(dent->d_name, "..") == 0 ||
811 strcmp(dent->d_name, "ftrace") == 0)
812 continue;
813 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2);
814 sprintf(sys, "%s/%s", path, dent->d_name);
815 ret = stat(sys, &st);
816 if (ret >= 0) {
817 if (S_ISDIR(st.st_mode)) {
818 write_or_die(dent->d_name, strlen(dent->d_name) + 1);
819 copy_event_system(sys);
820 }
821 }
822 free(sys);
823 }
824
825 put_tracing_file(path);
826}
827
828static void read_proc_kallsyms(void)
829{
830 unsigned int size, check_size;
831 const char *path = "/proc/kallsyms";
832 struct stat st;
833 int ret;
834
835 ret = stat(path, &st);
836 if (ret < 0) {
837 /* not found */
838 size = 0;
839 write_or_die(&size, 4);
840 return;
841 }
842 size = get_size(path);
843 write_or_die(&size, 4);
844 check_size = copy_file(path);
845 if (size != check_size)
846 die("error in size of file '%s'", path);
847
848}
849
850static void read_tracing_data(void)
851{
852 char buf[BUFSIZ];
853
854 output_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
855 if (output_fd < 0)
856 die("creating file '%s'", output_file);
857
858 buf[0] = 23;
859 buf[1] = 8;
860 buf[2] = 68;
861 memcpy(buf + 3, "tracing", 7);
862
863 write_or_die(buf, 10);
864
865 write_or_die(VERSION, strlen(VERSION) + 1);
866
867 if (bigendian())
868 buf[0] = 1;
869 else
870 buf[0] = 0;
871
872 write_or_die(buf, 1);
873
874 buf[0] = sizeof(long);
875 write_or_die(buf, 1);
876
877 read_header_files();
878 read_ftrace_files();
879 read_event_files();
880 read_proc_kallsyms();
881}
882
883static unsigned long long read_thread_file(int cpu)
884{
885 unsigned long long size;
886 char *file;
887
888 file = malloc_or_die(strlen(output_file) + 20);
889 snprintf(file, MAX_PATH, "%s.cpu%d", output_file, cpu);
890
891 size = copy_file(file);
892 free(file);
893 return size;
894}
895
896static void read_trace_data(void)
897{
898 char *path;
899
900 write_or_die("latency ", 10);
901
902 path = get_tracing_file("trace");
903
904 copy_file(path);
905
906 put_tracing_file(path);
907}
908
909static void read_thread_data(void)
910{
911 unsigned long long offset, check_size;
912 unsigned long long *offsets;
913 unsigned long long *sizes;
914 unsigned long long size;
915 long long ret;
916 struct stat st;
917 char *file;
918 int i;
919
920 if (!cpu_count)
921 return;
922
923 /*
924 * Save the command lines;
925 */
926 file = get_tracing_file("saved_cmdlines");
927 size = get_size(file);
928 write_or_die(&size, 8);
929 check_size = copy_file(file);
930 if (size != check_size)
931 die("error in size of file '%s'", file);
932 put_tracing_file(file);
933
934 write_or_die(&cpu_count, 4);
935
936 if (latency) {
937 read_trace_data();
938 return;
939 }
940
941 write_or_die("flyrecord", 10);
942
943 offsets = malloc_or_die(sizeof(*offsets) * cpu_count);
944 sizes = malloc_or_die(sizeof(*sizes) * cpu_count);
945
946 offset = lseek(output_fd, 0, SEEK_CUR);
947
948 /* hold any extra data for data */
949 offset += cpu_count * (16);
950 offset = (offset + (PAGE_SIZE - 1)) & ~(PAGE_MASK);
951
952 for (i = 0; i < cpu_count; i++) {
953 file = malloc_or_die(strlen(output_file) + 20);
954 sprintf(file, "%s.cpu%d", output_file, i);
955 ret = stat(file, &st);
956 if (ret < 0)
957 die("can not stat '%s'", file);
958 free(file);
959 offsets[i] = offset;
960 sizes[i] = st.st_size;
961 offset += st.st_size;
962 offset = (offset + (PAGE_SIZE - 1)) & ~(PAGE_MASK);
963
964 write_or_die(&offsets[i], 8);
965 write_or_die(&sizes[i], 8);
966 }
967
968 for (i = 0; i < cpu_count; i++) {
969 printf("offset=%llx\n", offsets[i]);
970 ret = lseek64(output_fd, offsets[i], SEEK_SET);
971 if (ret < 0)
972 die("could not seek to %lld\n", offsets[i]);
973 check_size = read_thread_file(i);
974 if (check_size != sizes[i])
975 die("did not match size of %lld to %lld",
976 check_size, sizes[i]);
977 }
978}
979
980void usage(char **argv)
981{
982 char *arg = argv[0];
983 char *p = arg+strlen(arg);
984
985 while (p >= arg && *p != '/')
986 p--;
987 p++;
988
989 printf("\n"
990 "%s version %s\n\n"
991 "usage: %s record [-e event][-p plugin] [-d] [-o file] command ...\n"
992 " -e run command with event enabled\n"
993 " -p run command with plugin enabled\n"
994 " -d disable function tracer when running\n"
995 " -o data output file [default trace.dat]\n"
996 "\n"
997 " %s report [-i file] [--cpu cpu] [-e][-f]\n"
998 " -i input file [default trace.dat]\n"
999 " -e show file endianess\n"
1000 " -f show function list\n"
1001 "\n"
1002 " %s list [-e][-p]\n"
1003 " -e list available events\n"
1004 " -p list available plugins\n"
1005 "\n", p, VERSION, p, p, p);
1006 exit(-1);
1007}
1008
1009int main (int argc, char **argv)
1010{
1011 const char *plugin = NULL;
1012 const char *output = NULL;
1013 struct event_list *event;
1014 int disable = 0;
1015 int plug = 0;
1016 int events = 0;
1017
1018 int c;
1019
1020 if (argc < 2)
1021 usage(argv);
1022
1023 if (strcmp(argv[1], "report") == 0) {
1024 trace_report(argc, argv);
1025 exit(0);
1026 } else if (strcmp(argv[1], "record") == 0) {
1027
1028 while ((c = getopt(argc-1, argv+1, "+he:p:do:")) >= 0) {
1029 switch (c) {
1030 case 'h':
1031 usage(argv);
1032 break;
1033 case 'e':
1034 events = 1;
1035 event = malloc_or_die(sizeof(*event));
1036 event->event = optarg;
1037 event->next = event_selection;
1038 event_selection = event;
1039 break;
1040 case 'p':
1041 if (plugin)
1042 die("only one plugin allowed");
1043 plugin = optarg;
1044 printf(" plugin %s\n", plugin);
1045 break;
1046 case 'd':
1047 disable = 1;
1048 break;
1049 case 'o':
1050 if (output)
1051 die("only one output file allowed");
1052 output = optarg;
1053 }
1054 }
1055
1056 } else if (strcmp(argv[1], "list") == 0) {
1057
1058 while ((c = getopt(argc-1, argv+1, "+hep")) >= 0) {
1059 switch (c) {
1060 case 'h':
1061 usage(argv);
1062 break;
1063 case 'e':
1064 events = 1;
1065 break;
1066 case 'p':
1067 plug = 1;
1068 break;
1069 default:
1070 usage(argv);
1071 }
1072 }
1073
1074 if (events)
1075 show_events();
1076
1077 if (plug)
1078 show_plugins();
1079
1080 if (!events && !plug) {
1081 printf("events:\n");
1082 show_events();
1083 printf("\nplugins:\n");
1084 show_plugins();
1085 }
1086
1087 exit(0);
1088
1089 } else {
1090 fprintf(stderr, "unkown command: %s\n", argv[1]);
1091 usage(argv);
1092 }
1093
1094 if ((argc - optind) < 2)
1095 usage(argv);
1096
1097 if (output)
1098 output_file = output;
1099
1100 read_tracing_data();
1101
1102 set_ftrace(!disable);
1103
1104 disable_all();
1105
1106 start_threads();
1107
1108 signal(SIGINT, finish);
1109
1110 if (events)
1111 enable_events();
1112 if (plugin) {
1113 /*
1114 * Latency tracers just save the trace and kill
1115 * the threads.
1116 */
1117 if (strcmp(plugin, "irqsoff") == 0 ||
1118 strcmp(plugin, "preemptoff") == 0 ||
1119 strcmp(plugin, "preemptirqsoff") == 0 ||
1120 strcmp(plugin, "wakeup") == 0 ||
1121 strcmp(plugin, "wakeup_rt") == 0) {
1122 latency = 1;
1123 stop_threads();
1124 }
1125 set_plugin(plugin);
1126 }
1127
1128 enable_tracing();
1129
1130 run_cmd((argc - optind) - 1, &argv[optind + 1]);
1131
1132 disable_tracing();
1133
1134 stop_threads();
1135
1136 read_thread_data();
1137 delete_thread_data();
1138
1139 exit(0);
1140
1141 return 0;
1142}
1143
diff --git a/trace-read.c b/trace-read.c
new file mode 100644
index 0000000..6b6a93b
--- /dev/null
+++ b/trace-read.c
@@ -0,0 +1,604 @@
1#define _GNU_SOURCE
2#include <dirent.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <getopt.h>
7#include <stdarg.h>
8#include <sys/types.h>
9#include <sys/stat.h>
10#include <sys/wait.h>
11#include <sys/mman.h>
12#include <pthread.h>
13#include <fcntl.h>
14#include <unistd.h>
15#include <ctype.h>
16#include <errno.h>
17
18#include "parse-events.h"
19
20static int input_fd;
21
22static int file_bigendian;
23static int host_bigendian;
24static int long_size;
25
26static int filter_cpu = -1;
27
28static int bigendian(void)
29{
30 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 };
31 unsigned int *ptr;
32
33 ptr = (unsigned int *)str;
34 return *ptr == 0x01020304;
35}
36
37static int read_or_die(void *data, int size)
38{
39 int r;
40
41 r = read(input_fd, data, size);
42 if (r != size)
43 die("reading input file (size expected=%d received=%d)",
44 size, r);
45 return r;
46}
47
48static unsigned int __data2host4(unsigned int data)
49{
50 unsigned long long swap;
51
52 if (host_bigendian == file_bigendian)
53 return data;
54
55 swap = ((data & 0xffULL) << 24) |
56 ((data & (0xffULL << 8)) << 8) |
57 ((data & (0xffULL << 16)) >> 8) |
58 ((data & (0xffULL << 24)) >> 24);
59
60 return swap;
61}
62
63static unsigned long long __data2host8(unsigned long long data)
64{
65 unsigned long long swap;
66
67 if (host_bigendian == file_bigendian)
68 return data;
69
70 swap = ((data & 0xffULL) << 56) |
71 ((data & (0xffULL << 8)) << 40) |
72 ((data & (0xffULL << 16)) << 24) |
73 ((data & (0xffULL << 24)) << 8) |
74 ((data & (0xffULL << 32)) >> 8) |
75 ((data & (0xffULL << 40)) >> 24) |
76 ((data & (0xffULL << 48)) >> 40) |
77 ((data & (0xffULL << 56)) >> 56);
78
79 return swap;
80}
81
82#define data2host4(ptr) __data2host4(*(unsigned int *)ptr)
83#define data2host8(ptr) __data2host8(*(unsigned long long *)ptr)
84
85static unsigned int read4(void)
86{
87 unsigned int data;
88
89 read_or_die(&data, 4);
90 return __data2host4(data);
91}
92
93static unsigned long long read8(void)
94{
95 unsigned long long data;
96
97 read_or_die(&data, 8);
98 return __data2host8(data);
99}
100
101static char *read_string(void)
102{
103 char buf[BUFSIZ];
104 char *str = NULL;
105 int size = 0;
106 int i;
107 int r;
108
109 for (;;) {
110 r = read(input_fd, buf, BUFSIZ);
111 if (r < 0)
112 die("reading input file");
113
114 if (!r)
115 die("no data");
116
117 for (i = 0; i < r; i++) {
118 if (!buf[i])
119 break;
120 }
121 if (i < r)
122 break;
123
124 if (str) {
125 size += BUFSIZ;
126 str = realloc(str, size);
127 if (!str)
128 die("malloc of size %d", size);
129 memcpy(str + (size - BUFSIZ), buf, BUFSIZ);
130 } else {
131 size = BUFSIZ;
132 str = malloc_or_die(size);
133 memcpy(str, buf, size);
134 }
135 }
136
137 /* move the file descriptor to the end of the string */
138 r = lseek(input_fd, -(r - (i+1)), SEEK_CUR);
139 if (r < 0)
140 die("lseek");
141
142 if (str) {
143 size += i;
144 str = realloc(str, size);
145 if (!str)
146 die("malloc of size %d", size);
147 memcpy(str + (size - i), buf, i);
148 } else {
149 size = i;
150 str = malloc_or_die(i);
151 memcpy(str, buf, i);
152 }
153
154 return str;
155}
156
157static void read_proc_kallsyms(void)
158{
159 unsigned int size;
160 char *buf;
161
162 size = read4();
163 if (!size)
164 return;
165
166 buf = malloc_or_die(size);
167 read_or_die(buf, size);
168
169 parse_proc_kallsyms(buf, size);
170
171 free(buf);
172}
173
174static void read_header_files(void)
175{
176 unsigned long long size;
177 char *header_page;
178 char *header_event;
179 char buf[BUFSIZ];
180
181 read_or_die(buf, 12);
182 if (memcmp(buf, "header_page", 12) != 0)
183 die("did not read header page");
184
185 size = read8();
186 header_page = malloc_or_die(size);
187 read_or_die(header_page, size);
188 free(header_page);
189
190 read_or_die(buf, 13);
191 if (memcmp(buf, "header_event", 13) != 0)
192 die("did not read header event");
193
194 size = read8();
195 header_event = malloc_or_die(size);
196 read_or_die(header_event, size);
197 free(header_event);
198}
199
200static void read_ftrace_file(unsigned long long size)
201{
202 char *buf;
203
204 buf = malloc_or_die(size);
205 read_or_die(buf, size);
206 parse_ftrace_file(buf, size);
207 free(buf);
208}
209
210static void read_event_file(char *system, unsigned long long size)
211{
212 char *buf;
213
214 buf = malloc_or_die(size);
215 read_or_die(buf, size);
216 parse_event_file(buf, size, system);
217 free(buf);
218}
219
220static void read_ftrace_files(void)
221{
222 unsigned long long size;
223 int count;
224 int i;
225
226 count = read4();
227
228 for (i = 0; i < count; i++) {
229 size = read8();
230 read_ftrace_file(size);
231 }
232}
233
234static void read_event_files(void)
235{
236 unsigned long long size;
237 char *system;
238 int systems;
239 int count;
240 int i,x;
241
242 systems = read4();
243
244 for (i = 0; i < systems; i++) {
245 system = read_string();
246
247 count = read4();
248 for (x=0; x < count; x++) {
249 size = read8();
250 read_event_file(system, size);
251 }
252 }
253}
254
255struct cpu_data {
256 unsigned long long offset;
257 unsigned long long size;
258 unsigned long long timestamp;
259 struct record *next;
260 char *page;
261 int cpu;
262 int index;
263 int page_size;
264};
265
266static int cpus;
267static struct cpu_data *cpu_data;
268
269static void init_cpu(int cpu)
270{
271 if (!cpu_data[cpu].size) {
272 printf("CPU %d is empty\n", cpu);
273 return;
274 }
275
276 cpu_data[cpu].page = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE,
277 input_fd, cpu_data[cpu].offset);
278 if (cpu_data[cpu].page == MAP_FAILED)
279 die("failed to mmap cpu %d at offset 0x%llx",
280 cpu, cpu_data[cpu].offset);
281}
282
283static void get_next_page(int cpu)
284{
285 if (!cpu_data[cpu].page)
286 return;
287
288 munmap(cpu_data[cpu].page, PAGE_SIZE);
289 cpu_data[cpu].page = NULL;
290
291 if (cpu_data[cpu].size <= PAGE_SIZE)
292 return;
293
294 cpu_data[cpu].offset += PAGE_SIZE;
295 cpu_data[cpu].size -= PAGE_SIZE;
296 cpu_data[cpu].index = 0;
297
298 cpu_data[cpu].page = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE,
299 input_fd, cpu_data[cpu].offset);
300 if (cpu_data[cpu].page == MAP_FAILED)
301 die("failed to mmap cpu %d at offset 0x%llx",
302 cpu, cpu_data[cpu].offset);
303}
304
305static unsigned int type_len4host(unsigned int type_len_ts)
306{
307 return type_len_ts & ((1 << 5) - 1);
308}
309
310static unsigned int ts4host(unsigned int type_len_ts)
311{
312 return type_len_ts >> 5;
313}
314
315static int calc_index(void *ptr, int cpu)
316{
317 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
318}
319
320struct record *peak_data(int cpu)
321{
322 struct record *data;
323 void *page = cpu_data[cpu].page;
324 int index = cpu_data[cpu].index;
325 void *ptr = page + index;
326 unsigned long long extend;
327 unsigned int type_len_ts;
328 unsigned int type_len;
329 unsigned int delta;
330 unsigned int length;
331
332 if (cpu_data[cpu].next)
333 return cpu_data[cpu].next;
334
335 if (!page)
336 return NULL;
337
338 if (!index) {
339 /* FIXME: handle header page */
340 cpu_data[cpu].timestamp = data2host8(ptr);
341 ptr += 8;
342 cpu_data[cpu].page_size = data2host8(ptr);
343 ptr += 8;
344 }
345
346read_again:
347 index = calc_index(ptr, cpu);
348
349 if (index >= cpu_data[cpu].page_size) {
350 get_next_page(cpu);
351 return peak_data(cpu);
352 }
353
354 type_len_ts = data2host4(ptr);
355 ptr += 4;
356
357 type_len = type_len4host(type_len_ts);
358 delta = ts4host(type_len_ts);
359
360 switch (type_len) {
361 case RINGBUF_TYPE_PADDING:
362 if (!delta)
363 die("error, hit unexpected end of page");
364 length = data2host4(ptr);
365 ptr += 4;
366 length *= 4;
367 ptr += length;
368 goto read_again;
369
370 case RINGBUF_TYPE_TIME_EXTEND:
371 extend = data2host4(ptr);
372 ptr += 4;
373 extend <<= TS_SHIFT;
374 extend += delta;
375 cpu_data[cpu].timestamp += extend;
376 goto read_again;
377
378 case RINGBUF_TYPE_TIME_STAMP:
379 ptr += 12;
380 break;
381 case 0:
382 length = data2host4(ptr);
383 ptr += 4;
384 die("here! length=%d", length);
385 break;
386 default:
387 length = type_len * 4;
388 break;
389 }
390
391 cpu_data[cpu].timestamp += delta;
392
393 data = malloc_or_die(sizeof(*data));
394 memset(data, 0, sizeof(*data));
395
396 data->ts = cpu_data[cpu].timestamp;
397 data->size = length;
398 data->data = ptr;
399 ptr += length;
400
401 cpu_data[cpu].index = calc_index(ptr, cpu);
402 cpu_data[cpu].next = data;
403
404 return data;
405}
406
407struct record *read_data(int cpu)
408{
409 struct record *data;
410
411 data = peak_data(cpu);
412 cpu_data[cpu].next = NULL;
413
414 return data;
415}
416
417static void show_data(int cpu)
418{
419 struct record *record;
420
421 record = read_data(cpu);
422
423 print_event(cpu, record->data, record->size, record->ts);
424
425 free(record);
426}
427
428static void read_rest(void)
429{
430 char buf[BUFSIZ + 1];
431 int r;
432
433 do {
434 r = read(input_fd, buf, BUFSIZ);
435 if (r > 0) {
436 buf[r] = 0;
437 printf(buf);
438 }
439 } while (r > 0);
440}
441
442static void read_data_info(void)
443{
444 unsigned long long ts;
445 unsigned long long size;
446 char *cmdlines;
447 struct record *data;
448 char buf[10];
449 int cpu;
450 int next;
451
452 size = read8();
453 cmdlines = malloc_or_die(size);
454 read_or_die(cmdlines, size);
455 parse_cmdlines(cmdlines, size);
456 free(cmdlines);
457
458 cpus = read4();
459 printf("cpus=%d\n", cpus);
460
461 parse_set_info(cpus, long_size);
462
463 /*
464 * Check if this is a latency report or not.
465 */
466 read_or_die(buf, 10);
467 if (strncmp(buf, "latency", 7) == 0) {
468 read_rest();
469 return;
470 }
471
472 cpu_data = malloc_or_die(sizeof(*cpu_data) * cpus);
473 memset(cpu_data, 0, sizeof(*cpu_data) * cpus);
474
475 for (cpu = 0; cpu < cpus; cpu++) {
476 cpu_data[cpu].cpu = cpu;
477 cpu_data[cpu].offset = read8();
478 cpu_data[cpu].size = read8();
479
480 init_cpu(cpu);
481 }
482
483 do {
484 next = -1;
485 ts = 0;
486 if (filter_cpu >= 0) {
487 cpu = filter_cpu;
488 data = peak_data(cpu);
489 if (data)
490 next = cpu;
491 } else {
492 for (cpu = 0; cpu < cpus; cpu++) {
493 data = peak_data(cpu);
494 if (data && (!ts || data->ts < ts)) {
495 ts = data->ts;
496 next = cpu;
497 }
498 }
499 }
500 if (next >= 0)
501 show_data(next);
502
503 } while (next >= 0);
504}
505
506
507void trace_report (int argc, char **argv)
508{
509 const char *input_file = "trace.dat";
510 char buf[BUFSIZ];
511 char test[] = { 23, 8, 68 };
512 char *version;
513 int show_funcs = 0;
514 int show_endian = 0;
515 int c;
516
517 if (argc < 2)
518 usage(argv);
519
520 if (strcmp(argv[1], "report") != 0)
521 usage(argv);
522
523 for (;;) {
524 int option_index = 0;
525 static struct option long_options[] = {
526 {"cpu", required_argument, NULL, 0},
527 {"help", no_argument, NULL, '?'},
528 {NULL, 0, NULL, 0}
529 };
530
531 c = getopt_long (argc-1, argv+1, "+hi:fe",
532 long_options, &option_index);
533 if (c == -1)
534 break;
535 switch (c) {
536 case 'h':
537 usage(argv);
538 break;
539 case 'i':
540 input_file = optarg;
541 break;
542 case 'f':
543 show_funcs = 1;
544 break;
545 case 'e':
546 show_endian = 1;
547 break;
548 case 0:
549 switch(option_index) {
550 case 0:
551 filter_cpu = atoi(optarg);
552 break;
553 default:
554 usage(argv);
555 }
556 break;
557 default:
558 usage(argv);
559 }
560 }
561
562 input_fd = open(input_file, O_RDONLY);
563 if (input_fd < 0)
564 die("opening '%s'\n", input_file);
565
566 read_or_die(buf, 3);
567 if (memcmp(buf, test, 3) != 0)
568 die("not an trace data file");
569
570 read_or_die(buf, 7);
571 if (memcmp(buf, "tracing", 7) != 0)
572 die("not a trace file (missing tracing)");
573
574 version = read_string();
575 printf("version = %s\n", version);
576 free(version);
577
578 read_or_die(buf, 1);
579 file_bigendian = buf[0];
580 host_bigendian = bigendian();
581
582 read_or_die(buf, 1);
583 long_size = buf[0];
584
585 if (show_endian) {
586 printf("file is %s endian and host is %s endian\n",
587 file_bigendian ? "big" : "little",
588 host_bigendian ? "big" : "little");
589 return;
590 }
591
592 read_header_files();
593 read_ftrace_files();
594 read_event_files();
595 read_proc_kallsyms();
596
597 if (show_funcs) {
598 print_funcs();
599 return;
600 }
601 read_data_info();
602
603 return;
604}