aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2012-07-25 01:43:04 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2012-07-25 01:43:04 -0400
commit314820c9e892d8f41ba4db300ec96770d9c8294b (patch)
tree3d5c59a429239b180c77e57f998a78d3f2b79827 /tools/perf/util
parente76b8ee25e034ab601b525abb95cea14aa167ed3 (diff)
parent07b8481d4aff73d6f451f25e74ea10240ff5131e (diff)
Merge branch 'next' into for-linus
Diffstat (limited to 'tools/perf/util')
-rwxr-xr-xtools/perf/util/PERF-VERSION-GEN2
-rw-r--r--tools/perf/util/annotate.c599
-rw-r--r--tools/perf/util/annotate.h67
-rw-r--r--tools/perf/util/build-id.c2
-rw-r--r--tools/perf/util/cache.h24
-rw-r--r--tools/perf/util/callchain.c2
-rw-r--r--tools/perf/util/callchain.h2
-rw-r--r--tools/perf/util/config.c2
-rw-r--r--tools/perf/util/debug.c1
-rw-r--r--tools/perf/util/debug.h2
-rw-r--r--tools/perf/util/evlist.c33
-rw-r--r--tools/perf/util/evlist.h8
-rw-r--r--tools/perf/util/evsel.c140
-rw-r--r--tools/perf/util/evsel.h3
-rw-r--r--tools/perf/util/gtk/browser.c189
-rw-r--r--tools/perf/util/gtk/gtk.h8
-rw-r--r--tools/perf/util/header.c77
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/hist.c9
-rw-r--r--tools/perf/util/hist.h4
-rw-r--r--tools/perf/util/include/linux/bitops.h2
-rw-r--r--tools/perf/util/pager.c4
-rw-r--r--tools/perf/util/parse-events-test.c625
-rw-r--r--tools/perf/util/parse-events.c141
-rw-r--r--tools/perf/util/parse-events.h43
-rw-r--r--tools/perf/util/parse-events.l28
-rw-r--r--tools/perf/util/parse-events.y93
-rw-r--r--tools/perf/util/pmu.c74
-rw-r--r--tools/perf/util/probe-event.c418
-rw-r--r--tools/perf/util/probe-event.h12
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c16
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c16
-rw-r--r--tools/perf/util/session.c203
-rw-r--r--tools/perf/util/session.h1
-rw-r--r--tools/perf/util/symbol.c57
-rw-r--r--tools/perf/util/symbol.h36
-rw-r--r--tools/perf/util/target.c142
-rw-r--r--tools/perf/util/target.h65
-rw-r--r--tools/perf/util/thread_map.c21
-rw-r--r--tools/perf/util/thread_map.h2
-rw-r--r--tools/perf/util/top.c19
-rw-r--r--tools/perf/util/top.h6
-rw-r--r--tools/perf/util/trace-event-info.c4
-rw-r--r--tools/perf/util/trace-event-parse.c3142
-rw-r--r--tools/perf/util/trace-event-read.c44
-rw-r--r--tools/perf/util/trace-event.h269
-rw-r--r--tools/perf/util/types.h5
-rw-r--r--tools/perf/util/ui/browser.c597
-rw-r--r--tools/perf/util/ui/browser.h65
-rw-r--r--tools/perf/util/ui/browsers/annotate.c433
-rw-r--r--tools/perf/util/ui/browsers/hists.c1341
-rw-r--r--tools/perf/util/ui/browsers/map.c154
-rw-r--r--tools/perf/util/ui/browsers/map.h6
-rw-r--r--tools/perf/util/ui/helpline.c79
-rw-r--r--tools/perf/util/ui/helpline.h16
-rw-r--r--tools/perf/util/ui/keysyms.h27
-rw-r--r--tools/perf/util/ui/libslang.h29
-rw-r--r--tools/perf/util/ui/progress.c32
-rw-r--r--tools/perf/util/ui/progress.h8
-rw-r--r--tools/perf/util/ui/setup.c155
-rw-r--r--tools/perf/util/ui/ui.h11
-rw-r--r--tools/perf/util/ui/util.c250
-rw-r--r--tools/perf/util/ui/util.h14
-rw-r--r--tools/perf/util/usage.c38
-rw-r--r--tools/perf/util/util.c10
-rw-r--r--tools/perf/util/util.h5
66 files changed, 2821 insertions, 7113 deletions
diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN
index ad73300f7bac..95264f304179 100755
--- a/tools/perf/util/PERF-VERSION-GEN
+++ b/tools/perf/util/PERF-VERSION-GEN
@@ -12,7 +12,7 @@ LF='
12# First check if there is a .git to get the version from git describe 12# First check if there is a .git to get the version from git describe
13# otherwise try to get the version from the kernel makefile 13# otherwise try to get the version from the kernel makefile
14if test -d ../../.git -o -f ../../.git && 14if test -d ../../.git -o -f ../../.git &&
15 VN=$(git describe --abbrev=4 HEAD 2>/dev/null) && 15 VN=$(git describe --match 'v[0-9].[0-9]*' --abbrev=4 HEAD 2>/dev/null) &&
16 case "$VN" in 16 case "$VN" in
17 *$LF*) (exit 1) ;; 17 *$LF*) (exit 1) ;;
18 v[0-9]*) 18 v[0-9]*)
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 08c6d138a655..8069dfb5ba77 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -18,6 +18,403 @@
18 18
19const char *disassembler_style; 19const char *disassembler_style;
20 20
21static struct ins *ins__find(const char *name);
22static int disasm_line__parse(char *line, char **namep, char **rawp);
23
24static void ins__delete(struct ins_operands *ops)
25{
26 free(ops->source.raw);
27 free(ops->source.name);
28 free(ops->target.raw);
29 free(ops->target.name);
30}
31
32static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
33 struct ins_operands *ops)
34{
35 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw);
36}
37
38int ins__scnprintf(struct ins *ins, char *bf, size_t size,
39 struct ins_operands *ops)
40{
41 if (ins->ops->scnprintf)
42 return ins->ops->scnprintf(ins, bf, size, ops);
43
44 return ins__raw_scnprintf(ins, bf, size, ops);
45}
46
47static int call__parse(struct ins_operands *ops)
48{
49 char *endptr, *tok, *name;
50
51 ops->target.addr = strtoull(ops->raw, &endptr, 16);
52
53 name = strchr(endptr, '<');
54 if (name == NULL)
55 goto indirect_call;
56
57 name++;
58
59 tok = strchr(name, '>');
60 if (tok == NULL)
61 return -1;
62
63 *tok = '\0';
64 ops->target.name = strdup(name);
65 *tok = '>';
66
67 return ops->target.name == NULL ? -1 : 0;
68
69indirect_call:
70 tok = strchr(endptr, '(');
71 if (tok != NULL) {
72 ops->target.addr = 0;
73 return 0;
74 }
75
76 tok = strchr(endptr, '*');
77 if (tok == NULL)
78 return -1;
79
80 ops->target.addr = strtoull(tok + 1, NULL, 16);
81 return 0;
82}
83
84static int call__scnprintf(struct ins *ins, char *bf, size_t size,
85 struct ins_operands *ops)
86{
87 if (ops->target.name)
88 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name);
89
90 if (ops->target.addr == 0)
91 return ins__raw_scnprintf(ins, bf, size, ops);
92
93 return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr);
94}
95
96static struct ins_ops call_ops = {
97 .parse = call__parse,
98 .scnprintf = call__scnprintf,
99};
100
101bool ins__is_call(const struct ins *ins)
102{
103 return ins->ops == &call_ops;
104}
105
106static int jump__parse(struct ins_operands *ops)
107{
108 const char *s = strchr(ops->raw, '+');
109
110 ops->target.addr = strtoll(ops->raw, NULL, 16);
111
112 if (s++ != NULL)
113 ops->target.offset = strtoll(s, NULL, 16);
114 else
115 ops->target.offset = UINT64_MAX;
116
117 return 0;
118}
119
120static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
121 struct ins_operands *ops)
122{
123 return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset);
124}
125
126static struct ins_ops jump_ops = {
127 .parse = jump__parse,
128 .scnprintf = jump__scnprintf,
129};
130
131bool ins__is_jump(const struct ins *ins)
132{
133 return ins->ops == &jump_ops;
134}
135
136static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
137{
138 char *endptr, *name, *t;
139
140 if (strstr(raw, "(%rip)") == NULL)
141 return 0;
142
143 *addrp = strtoull(comment, &endptr, 16);
144 name = strchr(endptr, '<');
145 if (name == NULL)
146 return -1;
147
148 name++;
149
150 t = strchr(name, '>');
151 if (t == NULL)
152 return 0;
153
154 *t = '\0';
155 *namep = strdup(name);
156 *t = '>';
157
158 return 0;
159}
160
161static int lock__parse(struct ins_operands *ops)
162{
163 char *name;
164
165 ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
166 if (ops->locked.ops == NULL)
167 return 0;
168
169 if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0)
170 goto out_free_ops;
171
172 ops->locked.ins = ins__find(name);
173 if (ops->locked.ins == NULL)
174 goto out_free_ops;
175
176 if (!ops->locked.ins->ops)
177 return 0;
178
179 if (ops->locked.ins->ops->parse)
180 ops->locked.ins->ops->parse(ops->locked.ops);
181
182 return 0;
183
184out_free_ops:
185 free(ops->locked.ops);
186 ops->locked.ops = NULL;
187 return 0;
188}
189
190static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
191 struct ins_operands *ops)
192{
193 int printed;
194
195 if (ops->locked.ins == NULL)
196 return ins__raw_scnprintf(ins, bf, size, ops);
197
198 printed = scnprintf(bf, size, "%-6.6s ", ins->name);
199 return printed + ins__scnprintf(ops->locked.ins, bf + printed,
200 size - printed, ops->locked.ops);
201}
202
203static void lock__delete(struct ins_operands *ops)
204{
205 free(ops->locked.ops);
206 free(ops->target.raw);
207 free(ops->target.name);
208}
209
210static struct ins_ops lock_ops = {
211 .free = lock__delete,
212 .parse = lock__parse,
213 .scnprintf = lock__scnprintf,
214};
215
216static int mov__parse(struct ins_operands *ops)
217{
218 char *s = strchr(ops->raw, ','), *target, *comment, prev;
219
220 if (s == NULL)
221 return -1;
222
223 *s = '\0';
224 ops->source.raw = strdup(ops->raw);
225 *s = ',';
226
227 if (ops->source.raw == NULL)
228 return -1;
229
230 target = ++s;
231
232 while (s[0] != '\0' && !isspace(s[0]))
233 ++s;
234 prev = *s;
235 *s = '\0';
236
237 ops->target.raw = strdup(target);
238 *s = prev;
239
240 if (ops->target.raw == NULL)
241 goto out_free_source;
242
243 comment = strchr(s, '#');
244 if (comment == NULL)
245 return 0;
246
247 while (comment[0] != '\0' && isspace(comment[0]))
248 ++comment;
249
250 comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name);
251 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
252
253 return 0;
254
255out_free_source:
256 free(ops->source.raw);
257 ops->source.raw = NULL;
258 return -1;
259}
260
261static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
262 struct ins_operands *ops)
263{
264 return scnprintf(bf, size, "%-6.6s %s,%s", ins->name,
265 ops->source.name ?: ops->source.raw,
266 ops->target.name ?: ops->target.raw);
267}
268
269static struct ins_ops mov_ops = {
270 .parse = mov__parse,
271 .scnprintf = mov__scnprintf,
272};
273
274static int dec__parse(struct ins_operands *ops)
275{
276 char *target, *comment, *s, prev;
277
278 target = s = ops->raw;
279
280 while (s[0] != '\0' && !isspace(s[0]))
281 ++s;
282 prev = *s;
283 *s = '\0';
284
285 ops->target.raw = strdup(target);
286 *s = prev;
287
288 if (ops->target.raw == NULL)
289 return -1;
290
291 comment = strchr(s, '#');
292 if (comment == NULL)
293 return 0;
294
295 while (comment[0] != '\0' && isspace(comment[0]))
296 ++comment;
297
298 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
299
300 return 0;
301}
302
303static int dec__scnprintf(struct ins *ins, char *bf, size_t size,
304 struct ins_operands *ops)
305{
306 return scnprintf(bf, size, "%-6.6s %s", ins->name,
307 ops->target.name ?: ops->target.raw);
308}
309
310static struct ins_ops dec_ops = {
311 .parse = dec__parse,
312 .scnprintf = dec__scnprintf,
313};
314
315static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size,
316 struct ins_operands *ops __used)
317{
318 return scnprintf(bf, size, "%-6.6s", "nop");
319}
320
321static struct ins_ops nop_ops = {
322 .scnprintf = nop__scnprintf,
323};
324
325/*
326 * Must be sorted by name!
327 */
328static struct ins instructions[] = {
329 { .name = "add", .ops = &mov_ops, },
330 { .name = "addl", .ops = &mov_ops, },
331 { .name = "addq", .ops = &mov_ops, },
332 { .name = "addw", .ops = &mov_ops, },
333 { .name = "and", .ops = &mov_ops, },
334 { .name = "bts", .ops = &mov_ops, },
335 { .name = "call", .ops = &call_ops, },
336 { .name = "callq", .ops = &call_ops, },
337 { .name = "cmp", .ops = &mov_ops, },
338 { .name = "cmpb", .ops = &mov_ops, },
339 { .name = "cmpl", .ops = &mov_ops, },
340 { .name = "cmpq", .ops = &mov_ops, },
341 { .name = "cmpw", .ops = &mov_ops, },
342 { .name = "cmpxch", .ops = &mov_ops, },
343 { .name = "dec", .ops = &dec_ops, },
344 { .name = "decl", .ops = &dec_ops, },
345 { .name = "imul", .ops = &mov_ops, },
346 { .name = "inc", .ops = &dec_ops, },
347 { .name = "incl", .ops = &dec_ops, },
348 { .name = "ja", .ops = &jump_ops, },
349 { .name = "jae", .ops = &jump_ops, },
350 { .name = "jb", .ops = &jump_ops, },
351 { .name = "jbe", .ops = &jump_ops, },
352 { .name = "jc", .ops = &jump_ops, },
353 { .name = "jcxz", .ops = &jump_ops, },
354 { .name = "je", .ops = &jump_ops, },
355 { .name = "jecxz", .ops = &jump_ops, },
356 { .name = "jg", .ops = &jump_ops, },
357 { .name = "jge", .ops = &jump_ops, },
358 { .name = "jl", .ops = &jump_ops, },
359 { .name = "jle", .ops = &jump_ops, },
360 { .name = "jmp", .ops = &jump_ops, },
361 { .name = "jmpq", .ops = &jump_ops, },
362 { .name = "jna", .ops = &jump_ops, },
363 { .name = "jnae", .ops = &jump_ops, },
364 { .name = "jnb", .ops = &jump_ops, },
365 { .name = "jnbe", .ops = &jump_ops, },
366 { .name = "jnc", .ops = &jump_ops, },
367 { .name = "jne", .ops = &jump_ops, },
368 { .name = "jng", .ops = &jump_ops, },
369 { .name = "jnge", .ops = &jump_ops, },
370 { .name = "jnl", .ops = &jump_ops, },
371 { .name = "jnle", .ops = &jump_ops, },
372 { .name = "jno", .ops = &jump_ops, },
373 { .name = "jnp", .ops = &jump_ops, },
374 { .name = "jns", .ops = &jump_ops, },
375 { .name = "jnz", .ops = &jump_ops, },
376 { .name = "jo", .ops = &jump_ops, },
377 { .name = "jp", .ops = &jump_ops, },
378 { .name = "jpe", .ops = &jump_ops, },
379 { .name = "jpo", .ops = &jump_ops, },
380 { .name = "jrcxz", .ops = &jump_ops, },
381 { .name = "js", .ops = &jump_ops, },
382 { .name = "jz", .ops = &jump_ops, },
383 { .name = "lea", .ops = &mov_ops, },
384 { .name = "lock", .ops = &lock_ops, },
385 { .name = "mov", .ops = &mov_ops, },
386 { .name = "movb", .ops = &mov_ops, },
387 { .name = "movdqa",.ops = &mov_ops, },
388 { .name = "movl", .ops = &mov_ops, },
389 { .name = "movq", .ops = &mov_ops, },
390 { .name = "movslq", .ops = &mov_ops, },
391 { .name = "movzbl", .ops = &mov_ops, },
392 { .name = "movzwl", .ops = &mov_ops, },
393 { .name = "nop", .ops = &nop_ops, },
394 { .name = "nopl", .ops = &nop_ops, },
395 { .name = "nopw", .ops = &nop_ops, },
396 { .name = "or", .ops = &mov_ops, },
397 { .name = "orl", .ops = &mov_ops, },
398 { .name = "test", .ops = &mov_ops, },
399 { .name = "testb", .ops = &mov_ops, },
400 { .name = "testl", .ops = &mov_ops, },
401 { .name = "xadd", .ops = &mov_ops, },
402};
403
404static int ins__cmp(const void *name, const void *insp)
405{
406 const struct ins *ins = insp;
407
408 return strcmp(name, ins->name);
409}
410
411static struct ins *ins__find(const char *name)
412{
413 const int nmemb = ARRAY_SIZE(instructions);
414
415 return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp);
416}
417
21int symbol__annotate_init(struct map *map __used, struct symbol *sym) 418int symbol__annotate_init(struct map *map __used, struct symbol *sym)
22{ 419{
23 struct annotation *notes = symbol__annotation(sym); 420 struct annotation *notes = symbol__annotation(sym);
@@ -28,7 +425,7 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym)
28int symbol__alloc_hist(struct symbol *sym) 425int symbol__alloc_hist(struct symbol *sym)
29{ 426{
30 struct annotation *notes = symbol__annotation(sym); 427 struct annotation *notes = symbol__annotation(sym);
31 const size_t size = sym->end - sym->start + 1; 428 const size_t size = symbol__size(sym);
32 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); 429 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
33 430
34 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); 431 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
@@ -78,31 +475,110 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
78 return 0; 475 return 0;
79} 476}
80 477
81static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize) 478static void disasm_line__init_ins(struct disasm_line *dl)
479{
480 dl->ins = ins__find(dl->name);
481
482 if (dl->ins == NULL)
483 return;
484
485 if (!dl->ins->ops)
486 return;
487
488 if (dl->ins->ops->parse)
489 dl->ins->ops->parse(&dl->ops);
490}
491
492static int disasm_line__parse(char *line, char **namep, char **rawp)
493{
494 char *name = line, tmp;
495
496 while (isspace(name[0]))
497 ++name;
498
499 if (name[0] == '\0')
500 return -1;
501
502 *rawp = name + 1;
503
504 while ((*rawp)[0] != '\0' && !isspace((*rawp)[0]))
505 ++*rawp;
506
507 tmp = (*rawp)[0];
508 (*rawp)[0] = '\0';
509 *namep = strdup(name);
510
511 if (*namep == NULL)
512 goto out_free_name;
513
514 (*rawp)[0] = tmp;
515
516 if ((*rawp)[0] != '\0') {
517 (*rawp)++;
518 while (isspace((*rawp)[0]))
519 ++(*rawp);
520 }
521
522 return 0;
523
524out_free_name:
525 free(*namep);
526 *namep = NULL;
527 return -1;
528}
529
530static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
82{ 531{
83 struct objdump_line *self = malloc(sizeof(*self) + privsize); 532 struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
84 533
85 if (self != NULL) { 534 if (dl != NULL) {
86 self->offset = offset; 535 dl->offset = offset;
87 self->line = line; 536 dl->line = strdup(line);
537 if (dl->line == NULL)
538 goto out_delete;
539
540 if (offset != -1) {
541 if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0)
542 goto out_free_line;
543
544 disasm_line__init_ins(dl);
545 }
88 } 546 }
89 547
90 return self; 548 return dl;
549
550out_free_line:
551 free(dl->line);
552out_delete:
553 free(dl);
554 return NULL;
555}
556
557void disasm_line__free(struct disasm_line *dl)
558{
559 free(dl->line);
560 free(dl->name);
561 if (dl->ins && dl->ins->ops->free)
562 dl->ins->ops->free(&dl->ops);
563 else
564 ins__delete(&dl->ops);
565 free(dl);
91} 566}
92 567
93void objdump_line__free(struct objdump_line *self) 568int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw)
94{ 569{
95 free(self->line); 570 if (raw || !dl->ins)
96 free(self); 571 return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw);
572
573 return ins__scnprintf(dl->ins, bf, size, &dl->ops);
97} 574}
98 575
99static void objdump__add_line(struct list_head *head, struct objdump_line *line) 576static void disasm__add(struct list_head *head, struct disasm_line *line)
100{ 577{
101 list_add_tail(&line->node, head); 578 list_add_tail(&line->node, head);
102} 579}
103 580
104struct objdump_line *objdump__get_next_ip_line(struct list_head *head, 581struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos)
105 struct objdump_line *pos)
106{ 582{
107 list_for_each_entry_continue(pos, head, node) 583 list_for_each_entry_continue(pos, head, node)
108 if (pos->offset >= 0) 584 if (pos->offset >= 0)
@@ -111,15 +587,14 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
111 return NULL; 587 return NULL;
112} 588}
113 589
114static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, 590static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
115 int evidx, u64 len, int min_pcnt, 591 int evidx, u64 len, int min_pcnt, int printed,
116 int printed, int max_lines, 592 int max_lines, struct disasm_line *queue)
117 struct objdump_line *queue)
118{ 593{
119 static const char *prev_line; 594 static const char *prev_line;
120 static const char *prev_color; 595 static const char *prev_color;
121 596
122 if (oline->offset != -1) { 597 if (dl->offset != -1) {
123 const char *path = NULL; 598 const char *path = NULL;
124 unsigned int hits = 0; 599 unsigned int hits = 0;
125 double percent = 0.0; 600 double percent = 0.0;
@@ -127,10 +602,11 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
127 struct annotation *notes = symbol__annotation(sym); 602 struct annotation *notes = symbol__annotation(sym);
128 struct source_line *src_line = notes->src->lines; 603 struct source_line *src_line = notes->src->lines;
129 struct sym_hist *h = annotation__histogram(notes, evidx); 604 struct sym_hist *h = annotation__histogram(notes, evidx);
130 s64 offset = oline->offset; 605 s64 offset = dl->offset;
131 struct objdump_line *next; 606 const u64 addr = start + offset;
607 struct disasm_line *next;
132 608
133 next = objdump__get_next_ip_line(&notes->src->source, oline); 609 next = disasm__get_next_ip_line(&notes->src->source, dl);
134 610
135 while (offset < (s64)len && 611 while (offset < (s64)len &&
136 (next == NULL || offset < next->offset)) { 612 (next == NULL || offset < next->offset)) {
@@ -155,9 +631,9 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
155 631
156 if (queue != NULL) { 632 if (queue != NULL) {
157 list_for_each_entry_from(queue, &notes->src->source, node) { 633 list_for_each_entry_from(queue, &notes->src->source, node) {
158 if (queue == oline) 634 if (queue == dl)
159 break; 635 break;
160 objdump_line__print(queue, sym, evidx, len, 636 disasm_line__print(queue, sym, start, evidx, len,
161 0, 0, 1, NULL); 637 0, 0, 1, NULL);
162 } 638 }
163 } 639 }
@@ -180,17 +656,18 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
180 656
181 color_fprintf(stdout, color, " %7.2f", percent); 657 color_fprintf(stdout, color, " %7.2f", percent);
182 printf(" : "); 658 printf(" : ");
183 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line); 659 color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr);
660 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
184 } else if (max_lines && printed >= max_lines) 661 } else if (max_lines && printed >= max_lines)
185 return 1; 662 return 1;
186 else { 663 else {
187 if (queue) 664 if (queue)
188 return -1; 665 return -1;
189 666
190 if (!*oline->line) 667 if (!*dl->line)
191 printf(" :\n"); 668 printf(" :\n");
192 else 669 else
193 printf(" : %s\n", oline->line); 670 printf(" : %s\n", dl->line);
194 } 671 }
195 672
196 return 0; 673 return 0;
@@ -200,8 +677,8 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
200 FILE *file, size_t privsize) 677 FILE *file, size_t privsize)
201{ 678{
202 struct annotation *notes = symbol__annotation(sym); 679 struct annotation *notes = symbol__annotation(sym);
203 struct objdump_line *objdump_line; 680 struct disasm_line *dl;
204 char *line = NULL, *tmp, *tmp2, *c; 681 char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
205 size_t line_len; 682 size_t line_len;
206 s64 line_ip, offset = -1; 683 s64 line_ip, offset = -1;
207 684
@@ -219,6 +696,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
219 *c = 0; 696 *c = 0;
220 697
221 line_ip = -1; 698 line_ip = -1;
699 parsed_line = line;
222 700
223 /* 701 /*
224 * Strip leading spaces: 702 * Strip leading spaces:
@@ -246,14 +724,17 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
246 offset = line_ip - start; 724 offset = line_ip - start;
247 if (offset < 0 || (u64)line_ip > end) 725 if (offset < 0 || (u64)line_ip > end)
248 offset = -1; 726 offset = -1;
727 else
728 parsed_line = tmp2 + 1;
249 } 729 }
250 730
251 objdump_line = objdump_line__new(offset, line, privsize); 731 dl = disasm_line__new(offset, parsed_line, privsize);
252 if (objdump_line == NULL) { 732 free(line);
253 free(line); 733
734 if (dl == NULL)
254 return -1; 735 return -1;
255 } 736
256 objdump__add_line(&notes->src->source, objdump_line); 737 disasm__add(&notes->src->source, dl);
257 738
258 return 0; 739 return 0;
259} 740}
@@ -476,7 +957,7 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx)
476{ 957{
477 struct annotation *notes = symbol__annotation(sym); 958 struct annotation *notes = symbol__annotation(sym);
478 struct sym_hist *h = annotation__histogram(notes, evidx); 959 struct sym_hist *h = annotation__histogram(notes, evidx);
479 u64 len = sym->end - sym->start, offset; 960 u64 len = symbol__size(sym), offset;
480 961
481 for (offset = 0; offset < len; ++offset) 962 for (offset = 0; offset < len; ++offset)
482 if (h->addr[offset] != 0) 963 if (h->addr[offset] != 0)
@@ -492,7 +973,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
492 struct dso *dso = map->dso; 973 struct dso *dso = map->dso;
493 const char *filename = dso->long_name, *d_filename; 974 const char *filename = dso->long_name, *d_filename;
494 struct annotation *notes = symbol__annotation(sym); 975 struct annotation *notes = symbol__annotation(sym);
495 struct objdump_line *pos, *queue = NULL; 976 struct disasm_line *pos, *queue = NULL;
977 u64 start = map__rip_2objdump(map, sym->start);
496 int printed = 2, queue_len = 0; 978 int printed = 2, queue_len = 0;
497 int more = 0; 979 int more = 0;
498 u64 len; 980 u64 len;
@@ -502,7 +984,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
502 else 984 else
503 d_filename = basename(filename); 985 d_filename = basename(filename);
504 986
505 len = sym->end - sym->start; 987 len = symbol__size(sym);
506 988
507 printf(" Percent | Source code & Disassembly of %s\n", d_filename); 989 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
508 printf("------------------------------------------------\n"); 990 printf("------------------------------------------------\n");
@@ -516,8 +998,9 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
516 queue_len = 0; 998 queue_len = 0;
517 } 999 }
518 1000
519 switch (objdump_line__print(pos, sym, evidx, len, min_pcnt, 1001 switch (disasm_line__print(pos, sym, start, evidx, len,
520 printed, max_lines, queue)) { 1002 min_pcnt, printed, max_lines,
1003 queue)) {
521 case 0: 1004 case 0:
522 ++printed; 1005 ++printed;
523 if (context) { 1006 if (context) {
@@ -561,7 +1044,7 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
561{ 1044{
562 struct annotation *notes = symbol__annotation(sym); 1045 struct annotation *notes = symbol__annotation(sym);
563 struct sym_hist *h = annotation__histogram(notes, evidx); 1046 struct sym_hist *h = annotation__histogram(notes, evidx);
564 int len = sym->end - sym->start, offset; 1047 int len = symbol__size(sym), offset;
565 1048
566 h->sum = 0; 1049 h->sum = 0;
567 for (offset = 0; offset < len; ++offset) { 1050 for (offset = 0; offset < len; ++offset) {
@@ -570,14 +1053,42 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
570 } 1053 }
571} 1054}
572 1055
573void objdump_line_list__purge(struct list_head *head) 1056void disasm__purge(struct list_head *head)
574{ 1057{
575 struct objdump_line *pos, *n; 1058 struct disasm_line *pos, *n;
576 1059
577 list_for_each_entry_safe(pos, n, head, node) { 1060 list_for_each_entry_safe(pos, n, head, node) {
578 list_del(&pos->node); 1061 list_del(&pos->node);
579 objdump_line__free(pos); 1062 disasm_line__free(pos);
1063 }
1064}
1065
1066static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
1067{
1068 size_t printed;
1069
1070 if (dl->offset == -1)
1071 return fprintf(fp, "%s\n", dl->line);
1072
1073 printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name);
1074
1075 if (dl->ops.raw[0] != '\0') {
1076 printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
1077 dl->ops.raw);
580 } 1078 }
1079
1080 return printed + fprintf(fp, "\n");
1081}
1082
1083size_t disasm__fprintf(struct list_head *head, FILE *fp)
1084{
1085 struct disasm_line *pos;
1086 size_t printed = 0;
1087
1088 list_for_each_entry(pos, head, node)
1089 printed += disasm_line__fprintf(pos, fp);
1090
1091 return printed;
581} 1092}
582 1093
583int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 1094int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
@@ -592,7 +1103,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
592 if (symbol__annotate(sym, map, 0) < 0) 1103 if (symbol__annotate(sym, map, 0) < 0)
593 return -1; 1104 return -1;
594 1105
595 len = sym->end - sym->start; 1106 len = symbol__size(sym);
596 1107
597 if (print_lines) { 1108 if (print_lines) {
598 symbol__get_source_line(sym, map, evidx, &source_line, 1109 symbol__get_source_line(sym, map, evidx, &source_line,
@@ -605,7 +1116,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
605 if (print_lines) 1116 if (print_lines)
606 symbol__free_source_line(sym, len); 1117 symbol__free_source_line(sym, len);
607 1118
608 objdump_line_list__purge(&symbol__annotation(sym)->src->source); 1119 disasm__purge(&symbol__annotation(sym)->src->source);
609 1120
610 return 0; 1121 return 0;
611} 1122}
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index efa5dc82bfae..78a5692dd718 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -2,20 +2,69 @@
2#define __PERF_ANNOTATE_H 2#define __PERF_ANNOTATE_H
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include <stdint.h>
5#include "types.h" 6#include "types.h"
6#include "symbol.h" 7#include "symbol.h"
7#include <linux/list.h> 8#include <linux/list.h>
8#include <linux/rbtree.h> 9#include <linux/rbtree.h>
9 10
10struct objdump_line { 11struct ins;
11 struct list_head node; 12
12 s64 offset; 13struct ins_operands {
13 char *line; 14 char *raw;
15 struct {
16 char *raw;
17 char *name;
18 u64 addr;
19 u64 offset;
20 } target;
21 union {
22 struct {
23 char *raw;
24 char *name;
25 u64 addr;
26 } source;
27 struct {
28 struct ins *ins;
29 struct ins_operands *ops;
30 } locked;
31 };
14}; 32};
15 33
16void objdump_line__free(struct objdump_line *self); 34struct ins_ops {
17struct objdump_line *objdump__get_next_ip_line(struct list_head *head, 35 void (*free)(struct ins_operands *ops);
18 struct objdump_line *pos); 36 int (*parse)(struct ins_operands *ops);
37 int (*scnprintf)(struct ins *ins, char *bf, size_t size,
38 struct ins_operands *ops);
39};
40
41struct ins {
42 const char *name;
43 struct ins_ops *ops;
44};
45
46bool ins__is_jump(const struct ins *ins);
47bool ins__is_call(const struct ins *ins);
48int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops);
49
50struct disasm_line {
51 struct list_head node;
52 s64 offset;
53 char *line;
54 char *name;
55 struct ins *ins;
56 struct ins_operands ops;
57};
58
59static inline bool disasm_line__has_offset(const struct disasm_line *dl)
60{
61 return dl->ops.target.offset != UINT64_MAX;
62}
63
64void disasm_line__free(struct disasm_line *dl);
65struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos);
66int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw);
67size_t disasm__fprintf(struct list_head *head, FILE *fp);
19 68
20struct sym_hist { 69struct sym_hist {
21 u64 sum; 70 u64 sum;
@@ -32,7 +81,7 @@ struct source_line {
32 * 81 *
33 * @histogram: Array of addr hit histograms per event being monitored 82 * @histogram: Array of addr hit histograms per event being monitored
34 * @lines: If 'print_lines' is specified, per source code line percentages 83 * @lines: If 'print_lines' is specified, per source code line percentages
35 * @source: source parsed from objdump -dS 84 * @source: source parsed from a disassembler like objdump -dS
36 * 85 *
37 * lines is allocated, percentages calculated and all sorted by percentage 86 * lines is allocated, percentages calculated and all sorted by percentage
38 * when the annotation is about to be presented, so the percentages are for 87 * when the annotation is about to be presented, so the percentages are for
@@ -82,7 +131,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
82 int context); 131 int context);
83void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); 132void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
84void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); 133void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
85void objdump_line_list__purge(struct list_head *head); 134void disasm__purge(struct list_head *head);
86 135
87int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 136int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
88 bool print_lines, bool full_paths, int min_pcnt, 137 bool print_lines, bool full_paths, int min_pcnt,
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index dff9c7a725f4..fd9a5944b627 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -65,6 +65,8 @@ struct perf_tool build_id__mark_dso_hit_ops = {
65 .mmap = perf_event__process_mmap, 65 .mmap = perf_event__process_mmap,
66 .fork = perf_event__process_task, 66 .fork = perf_event__process_task,
67 .exit = perf_event__exit_del_thread, 67 .exit = perf_event__exit_del_thread,
68 .attr = perf_event__process_attr,
69 .build_id = perf_event__process_build_id,
68}; 70};
69 71
70char *dso__build_id_filename(struct dso *self, char *bf, size_t size) 72char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 8dd224df3e54..cff18c617d13 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -33,7 +33,7 @@ extern int pager_use_color;
33 33
34extern int use_browser; 34extern int use_browser;
35 35
36#ifdef NO_NEWT_SUPPORT 36#if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)
37static inline void setup_browser(bool fallback_to_pager) 37static inline void setup_browser(bool fallback_to_pager)
38{ 38{
39 if (fallback_to_pager) 39 if (fallback_to_pager)
@@ -43,19 +43,29 @@ static inline void exit_browser(bool wait_for_ok __used) {}
43#else 43#else
44void setup_browser(bool fallback_to_pager); 44void setup_browser(bool fallback_to_pager);
45void exit_browser(bool wait_for_ok); 45void exit_browser(bool wait_for_ok);
46
47#ifdef NO_NEWT_SUPPORT
48static inline int ui__init(void)
49{
50 return -1;
51}
52static inline void ui__exit(bool wait_for_ok __used) {}
53#else
54int ui__init(void);
55void ui__exit(bool wait_for_ok);
46#endif 56#endif
47 57
48#ifdef NO_GTK2_SUPPORT 58#ifdef NO_GTK2_SUPPORT
49static inline void perf_gtk_setup_browser(int argc __used, const char *argv[] __used, bool fallback_to_pager) 59static inline int perf_gtk__init(void)
50{ 60{
51 if (fallback_to_pager) 61 return -1;
52 setup_pager();
53} 62}
54static inline void perf_gtk_exit_browser(bool wait_for_ok __used) {} 63static inline void perf_gtk__exit(bool wait_for_ok __used) {}
55#else 64#else
56void perf_gtk_setup_browser(int argc, const char *argv[], bool fallback_to_pager); 65int perf_gtk__init(void);
57void perf_gtk_exit_browser(bool wait_for_ok); 66void perf_gtk__exit(bool wait_for_ok);
58#endif 67#endif
68#endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
59 69
60char *alias_lookup(const char *alias); 70char *alias_lookup(const char *alias);
61int split_cmdline(char *cmdline, const char ***argv); 71int split_cmdline(char *cmdline, const char ***argv);
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 9f7106a8d9a4..3a6bff47614f 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -18,6 +18,8 @@
18#include "util.h" 18#include "util.h"
19#include "callchain.h" 19#include "callchain.h"
20 20
21__thread struct callchain_cursor callchain_cursor;
22
21bool ip_callchain__valid(struct ip_callchain *chain, 23bool ip_callchain__valid(struct ip_callchain *chain,
22 const union perf_event *event) 24 const union perf_event *event)
23{ 25{
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 7f9c0f1ae3a9..3bdb407f9cd9 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -76,6 +76,8 @@ struct callchain_cursor {
76 struct callchain_cursor_node *curr; 76 struct callchain_cursor_node *curr;
77}; 77};
78 78
79extern __thread struct callchain_cursor callchain_cursor;
80
79static inline void callchain_init(struct callchain_root *root) 81static inline void callchain_init(struct callchain_root *root)
80{ 82{
81 INIT_LIST_HEAD(&root->node.siblings); 83 INIT_LIST_HEAD(&root->node.siblings);
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 0deac6a14b65..6faa3a18bfbd 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -120,7 +120,7 @@ static char *parse_value(void)
120 120
121static inline int iskeychar(int c) 121static inline int iskeychar(int c)
122{ 122{
123 return isalnum(c) || c == '-'; 123 return isalnum(c) || c == '-' || c == '_';
124} 124}
125 125
126static int get_value(config_fn_t fn, void *data, char *name, unsigned int len) 126static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 26817daa2961..efb1fce259a4 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -11,6 +11,7 @@
11#include "event.h" 11#include "event.h"
12#include "debug.h" 12#include "debug.h"
13#include "util.h" 13#include "util.h"
14#include "target.h"
14 15
15int verbose; 16int verbose;
16bool dump_trace = false, quiet = false; 17bool dump_trace = false, quiet = false;
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index f2ce88d04f54..6bebe7f0a20c 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -26,7 +26,7 @@ static inline void ui_progress__update(u64 curr __used, u64 total __used,
26#else 26#else
27extern char ui_helpline__last_msg[]; 27extern char ui_helpline__last_msg[];
28int ui_helpline__show_help(const char *format, va_list ap); 28int ui_helpline__show_help(const char *format, va_list ap);
29#include "ui/progress.h" 29#include "../ui/progress.h"
30int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2))); 30int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
31#endif 31#endif
32 32
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 1986d8051bd1..7400fb3fc50c 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -11,6 +11,7 @@
11#include <poll.h> 11#include <poll.h>
12#include "cpumap.h" 12#include "cpumap.h"
13#include "thread_map.h" 13#include "thread_map.h"
14#include "target.h"
14#include "evlist.h" 15#include "evlist.h"
15#include "evsel.h" 16#include "evsel.h"
16#include <unistd.h> 17#include <unistd.h>
@@ -158,6 +159,17 @@ out_delete_partial_list:
158 return -1; 159 return -1;
159} 160}
160 161
162int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
163 struct perf_event_attr *attrs, size_t nr_attrs)
164{
165 size_t i;
166
167 for (i = 0; i < nr_attrs; i++)
168 event_attr_init(attrs + i);
169
170 return perf_evlist__add_attrs(evlist, attrs, nr_attrs);
171}
172
161static int trace_event__id(const char *evname) 173static int trace_event__id(const char *evname)
162{ 174{
163 char *filename, *colon; 175 char *filename, *colon;
@@ -262,7 +274,8 @@ void perf_evlist__disable(struct perf_evlist *evlist)
262 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 274 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
263 list_for_each_entry(pos, &evlist->entries, node) { 275 list_for_each_entry(pos, &evlist->entries, node) {
264 for (thread = 0; thread < evlist->threads->nr; thread++) 276 for (thread = 0; thread < evlist->threads->nr; thread++)
265 ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_DISABLE); 277 ioctl(FD(pos, cpu, thread),
278 PERF_EVENT_IOC_DISABLE, 0);
266 } 279 }
267 } 280 }
268} 281}
@@ -275,7 +288,8 @@ void perf_evlist__enable(struct perf_evlist *evlist)
275 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { 288 for (cpu = 0; cpu < evlist->cpus->nr; cpu++) {
276 list_for_each_entry(pos, &evlist->entries, node) { 289 list_for_each_entry(pos, &evlist->entries, node) {
277 for (thread = 0; thread < evlist->threads->nr; thread++) 290 for (thread = 0; thread < evlist->threads->nr; thread++)
278 ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE); 291 ioctl(FD(pos, cpu, thread),
292 PERF_EVENT_IOC_ENABLE, 0);
279 } 293 }
280 } 294 }
281} 295}
@@ -599,18 +613,21 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
599 return perf_evlist__mmap_per_cpu(evlist, prot, mask); 613 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
600} 614}
601 615
602int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, 616int perf_evlist__create_maps(struct perf_evlist *evlist,
603 const char *target_tid, uid_t uid, const char *cpu_list) 617 struct perf_target *target)
604{ 618{
605 evlist->threads = thread_map__new_str(target_pid, target_tid, uid); 619 evlist->threads = thread_map__new_str(target->pid, target->tid,
620 target->uid);
606 621
607 if (evlist->threads == NULL) 622 if (evlist->threads == NULL)
608 return -1; 623 return -1;
609 624
610 if (uid != UINT_MAX || (cpu_list == NULL && target_tid)) 625 if (perf_target__has_task(target))
626 evlist->cpus = cpu_map__dummy_new();
627 else if (!perf_target__has_cpu(target) && !target->uses_mmap)
611 evlist->cpus = cpu_map__dummy_new(); 628 evlist->cpus = cpu_map__dummy_new();
612 else 629 else
613 evlist->cpus = cpu_map__new(cpu_list); 630 evlist->cpus = cpu_map__new(target->cpu_list);
614 631
615 if (evlist->cpus == NULL) 632 if (evlist->cpus == NULL)
616 goto out_delete_threads; 633 goto out_delete_threads;
@@ -827,7 +844,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
827 exit(-1); 844 exit(-1);
828 } 845 }
829 846
830 if (!opts->system_wide && !opts->target_tid && !opts->target_pid) 847 if (perf_target__none(&opts->target))
831 evlist->threads->map[0] = evlist->workload.pid; 848 evlist->threads->map[0] = evlist->workload.pid;
832 849
833 close(child_ready_pipe[1]); 850 close(child_ready_pipe[1]);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 21f1c9e57f13..989bee9624c2 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -54,6 +54,8 @@ void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry);
54int perf_evlist__add_default(struct perf_evlist *evlist); 54int perf_evlist__add_default(struct perf_evlist *evlist);
55int perf_evlist__add_attrs(struct perf_evlist *evlist, 55int perf_evlist__add_attrs(struct perf_evlist *evlist,
56 struct perf_event_attr *attrs, size_t nr_attrs); 56 struct perf_event_attr *attrs, size_t nr_attrs);
57int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
58 struct perf_event_attr *attrs, size_t nr_attrs);
57int perf_evlist__add_tracepoints(struct perf_evlist *evlist, 59int perf_evlist__add_tracepoints(struct perf_evlist *evlist,
58 const char *tracepoints[], size_t nr_tracepoints); 60 const char *tracepoints[], size_t nr_tracepoints);
59int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist, 61int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist,
@@ -62,6 +64,8 @@ int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist,
62 64
63#define perf_evlist__add_attrs_array(evlist, array) \ 65#define perf_evlist__add_attrs_array(evlist, array) \
64 perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array)) 66 perf_evlist__add_attrs(evlist, array, ARRAY_SIZE(array))
67#define perf_evlist__add_default_attrs(evlist, array) \
68 __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array))
65 69
66#define perf_evlist__add_tracepoints_array(evlist, array) \ 70#define perf_evlist__add_tracepoints_array(evlist, array) \
67 perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array)) 71 perf_evlist__add_tracepoints(evlist, array, ARRAY_SIZE(array))
@@ -106,8 +110,8 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
106 evlist->threads = threads; 110 evlist->threads = threads;
107} 111}
108 112
109int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, 113int perf_evlist__create_maps(struct perf_evlist *evlist,
110 const char *tid, uid_t uid, const char *cpu_list); 114 struct perf_target *target);
111void perf_evlist__delete_maps(struct perf_evlist *evlist); 115void perf_evlist__delete_maps(struct perf_evlist *evlist);
112int perf_evlist__set_filters(struct perf_evlist *evlist); 116int perf_evlist__set_filters(struct perf_evlist *evlist);
113 117
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 8c13dbcb84b9..9f6cebd798ee 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -14,6 +14,8 @@
14#include "util.h" 14#include "util.h"
15#include "cpumap.h" 15#include "cpumap.h"
16#include "thread_map.h" 16#include "thread_map.h"
17#include "target.h"
18#include "../../include/linux/perf_event.h"
17 19
18#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) 20#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
19#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) 21#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
@@ -63,12 +65,102 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
63 return evsel; 65 return evsel;
64} 66}
65 67
68static const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX] = {
69 "cycles",
70 "instructions",
71 "cache-references",
72 "cache-misses",
73 "branches",
74 "branch-misses",
75 "bus-cycles",
76 "stalled-cycles-frontend",
77 "stalled-cycles-backend",
78 "ref-cycles",
79};
80
81const char *__perf_evsel__hw_name(u64 config)
82{
83 if (config < PERF_COUNT_HW_MAX && perf_evsel__hw_names[config])
84 return perf_evsel__hw_names[config];
85
86 return "unknown-hardware";
87}
88
89static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size)
90{
91 int colon = 0;
92 struct perf_event_attr *attr = &evsel->attr;
93 int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(attr->config));
94 bool exclude_guest_default = false;
95
96#define MOD_PRINT(context, mod) do { \
97 if (!attr->exclude_##context) { \
98 if (!colon) colon = r++; \
99 r += scnprintf(bf + r, size - r, "%c", mod); \
100 } } while(0)
101
102 if (attr->exclude_kernel || attr->exclude_user || attr->exclude_hv) {
103 MOD_PRINT(kernel, 'k');
104 MOD_PRINT(user, 'u');
105 MOD_PRINT(hv, 'h');
106 exclude_guest_default = true;
107 }
108
109 if (attr->precise_ip) {
110 if (!colon)
111 colon = r++;
112 r += scnprintf(bf + r, size - r, "%.*s", attr->precise_ip, "ppp");
113 exclude_guest_default = true;
114 }
115
116 if (attr->exclude_host || attr->exclude_guest == exclude_guest_default) {
117 MOD_PRINT(host, 'H');
118 MOD_PRINT(guest, 'G');
119 }
120#undef MOD_PRINT
121 if (colon)
122 bf[colon] = ':';
123 return r;
124}
125
126int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size)
127{
128 int ret;
129
130 switch (evsel->attr.type) {
131 case PERF_TYPE_RAW:
132 ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config);
133 break;
134
135 case PERF_TYPE_HARDWARE:
136 ret = perf_evsel__hw_name(evsel, bf, size);
137 break;
138 default:
139 /*
140 * FIXME
141 *
142 * This is the minimal perf_evsel__name so that we can
143 * reconstruct event names taking into account event modifiers.
144 *
145 * The old event_name uses it now for raw anr hw events, so that
146 * we don't drag all the parsing stuff into the python binding.
147 *
148 * On the next devel cycle the rest of the event naming will be
149 * brought here.
150 */
151 return 0;
152 }
153
154 return ret;
155}
156
66void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts, 157void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
67 struct perf_evsel *first) 158 struct perf_evsel *first)
68{ 159{
69 struct perf_event_attr *attr = &evsel->attr; 160 struct perf_event_attr *attr = &evsel->attr;
70 int track = !evsel->idx; /* only the first counter needs these */ 161 int track = !evsel->idx; /* only the first counter needs these */
71 162
163 attr->disabled = 1;
72 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1; 164 attr->sample_id_all = opts->sample_id_all_missing ? 0 : 1;
73 attr->inherit = !opts->no_inherit; 165 attr->inherit = !opts->no_inherit;
74 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | 166 attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -106,15 +198,15 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
106 if (opts->call_graph) 198 if (opts->call_graph)
107 attr->sample_type |= PERF_SAMPLE_CALLCHAIN; 199 attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
108 200
109 if (opts->system_wide) 201 if (perf_target__has_cpu(&opts->target))
110 attr->sample_type |= PERF_SAMPLE_CPU; 202 attr->sample_type |= PERF_SAMPLE_CPU;
111 203
112 if (opts->period) 204 if (opts->period)
113 attr->sample_type |= PERF_SAMPLE_PERIOD; 205 attr->sample_type |= PERF_SAMPLE_PERIOD;
114 206
115 if (!opts->sample_id_all_missing && 207 if (!opts->sample_id_all_missing &&
116 (opts->sample_time || opts->system_wide || 208 (opts->sample_time || !opts->no_inherit ||
117 !opts->no_inherit || opts->cpu_list)) 209 perf_target__has_cpu(&opts->target)))
118 attr->sample_type |= PERF_SAMPLE_TIME; 210 attr->sample_type |= PERF_SAMPLE_TIME;
119 211
120 if (opts->raw_samples) { 212 if (opts->raw_samples) {
@@ -135,9 +227,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
135 attr->mmap = track; 227 attr->mmap = track;
136 attr->comm = track; 228 attr->comm = track;
137 229
138 if (!opts->target_pid && !opts->target_tid && !opts->system_wide && 230 if (perf_target__none(&opts->target) &&
139 (!opts->group || evsel == first)) { 231 (!opts->group || evsel == first)) {
140 attr->disabled = 1;
141 attr->enable_on_exec = 1; 232 attr->enable_on_exec = 1;
142 } 233 }
143} 234}
@@ -403,16 +494,24 @@ int perf_evsel__open_per_thread(struct perf_evsel *evsel,
403} 494}
404 495
405static int perf_event__parse_id_sample(const union perf_event *event, u64 type, 496static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
406 struct perf_sample *sample) 497 struct perf_sample *sample,
498 bool swapped)
407{ 499{
408 const u64 *array = event->sample.array; 500 const u64 *array = event->sample.array;
501 union u64_swap u;
409 502
410 array += ((event->header.size - 503 array += ((event->header.size -
411 sizeof(event->header)) / sizeof(u64)) - 1; 504 sizeof(event->header)) / sizeof(u64)) - 1;
412 505
413 if (type & PERF_SAMPLE_CPU) { 506 if (type & PERF_SAMPLE_CPU) {
414 u32 *p = (u32 *)array; 507 u.val64 = *array;
415 sample->cpu = *p; 508 if (swapped) {
509 /* undo swap of u64, then swap on individual u32s */
510 u.val64 = bswap_64(u.val64);
511 u.val32[0] = bswap_32(u.val32[0]);
512 }
513
514 sample->cpu = u.val32[0];
416 array--; 515 array--;
417 } 516 }
418 517
@@ -432,9 +531,16 @@ static int perf_event__parse_id_sample(const union perf_event *event, u64 type,
432 } 531 }
433 532
434 if (type & PERF_SAMPLE_TID) { 533 if (type & PERF_SAMPLE_TID) {
435 u32 *p = (u32 *)array; 534 u.val64 = *array;
436 sample->pid = p[0]; 535 if (swapped) {
437 sample->tid = p[1]; 536 /* undo swap of u64, then swap on individual u32s */
537 u.val64 = bswap_64(u.val64);
538 u.val32[0] = bswap_32(u.val32[0]);
539 u.val32[1] = bswap_32(u.val32[1]);
540 }
541
542 sample->pid = u.val32[0];
543 sample->tid = u.val32[1];
438 } 544 }
439 545
440 return 0; 546 return 0;
@@ -461,10 +567,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
461 * used for cross-endian analysis. See git commit 65014ab3 567 * used for cross-endian analysis. See git commit 65014ab3
462 * for why this goofiness is needed. 568 * for why this goofiness is needed.
463 */ 569 */
464 union { 570 union u64_swap u;
465 u64 val64;
466 u32 val32[2];
467 } u;
468 571
469 memset(data, 0, sizeof(*data)); 572 memset(data, 0, sizeof(*data));
470 data->cpu = data->pid = data->tid = -1; 573 data->cpu = data->pid = data->tid = -1;
@@ -474,7 +577,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
474 if (event->header.type != PERF_RECORD_SAMPLE) { 577 if (event->header.type != PERF_RECORD_SAMPLE) {
475 if (!sample_id_all) 578 if (!sample_id_all)
476 return 0; 579 return 0;
477 return perf_event__parse_id_sample(event, type, data); 580 return perf_event__parse_id_sample(event, type, data, swapped);
478 } 581 }
479 582
480 array = event->sample.array; 583 array = event->sample.array;
@@ -607,10 +710,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
607 * used for cross-endian analysis. See git commit 65014ab3 710 * used for cross-endian analysis. See git commit 65014ab3
608 * for why this goofiness is needed. 711 * for why this goofiness is needed.
609 */ 712 */
610 union { 713 union u64_swap u;
611 u64 val64;
612 u32 val32[2];
613 } u;
614 714
615 array = event->sample.array; 715 array = event->sample.array;
616 716
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 3d6b3e4cb66b..4ba8b564e6f4 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -83,6 +83,9 @@ void perf_evsel__config(struct perf_evsel *evsel,
83 struct perf_record_opts *opts, 83 struct perf_record_opts *opts,
84 struct perf_evsel *first); 84 struct perf_evsel *first);
85 85
86const char* __perf_evsel__hw_name(u64 config);
87int perf_evsel__name(struct perf_evsel *evsel, char *bf, size_t size);
88
86int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); 89int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads);
87int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); 90int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads);
88int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); 91int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
diff --git a/tools/perf/util/gtk/browser.c b/tools/perf/util/gtk/browser.c
deleted file mode 100644
index 258352a2356c..000000000000
--- a/tools/perf/util/gtk/browser.c
+++ /dev/null
@@ -1,189 +0,0 @@
1#include "../evlist.h"
2#include "../cache.h"
3#include "../evsel.h"
4#include "../sort.h"
5#include "../hist.h"
6#include "gtk.h"
7
8#include <signal.h>
9
10#define MAX_COLUMNS 32
11
12void perf_gtk_setup_browser(int argc, const char *argv[],
13 bool fallback_to_pager __used)
14{
15 gtk_init(&argc, (char ***)&argv);
16}
17
18void perf_gtk_exit_browser(bool wait_for_ok __used)
19{
20 gtk_main_quit();
21}
22
23static void perf_gtk_signal(int sig)
24{
25 psignal(sig, "perf");
26 gtk_main_quit();
27}
28
29static void perf_gtk_resize_window(GtkWidget *window)
30{
31 GdkRectangle rect;
32 GdkScreen *screen;
33 int monitor;
34 int height;
35 int width;
36
37 screen = gtk_widget_get_screen(window);
38
39 monitor = gdk_screen_get_monitor_at_window(screen, window->window);
40
41 gdk_screen_get_monitor_geometry(screen, monitor, &rect);
42
43 width = rect.width * 3 / 4;
44 height = rect.height * 3 / 4;
45
46 gtk_window_resize(GTK_WINDOW(window), width, height);
47}
48
49static void perf_gtk_show_hists(GtkWidget *window, struct hists *hists)
50{
51 GType col_types[MAX_COLUMNS];
52 GtkCellRenderer *renderer;
53 struct sort_entry *se;
54 GtkListStore *store;
55 struct rb_node *nd;
56 u64 total_period;
57 GtkWidget *view;
58 int col_idx;
59 int nr_cols;
60
61 nr_cols = 0;
62
63 /* The percentage column */
64 col_types[nr_cols++] = G_TYPE_STRING;
65
66 list_for_each_entry(se, &hist_entry__sort_list, list) {
67 if (se->elide)
68 continue;
69
70 col_types[nr_cols++] = G_TYPE_STRING;
71 }
72
73 store = gtk_list_store_newv(nr_cols, col_types);
74
75 view = gtk_tree_view_new();
76
77 renderer = gtk_cell_renderer_text_new();
78
79 col_idx = 0;
80
81 /* The percentage column */
82 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
83 -1, "Overhead (%)",
84 renderer, "text",
85 col_idx++, NULL);
86
87 list_for_each_entry(se, &hist_entry__sort_list, list) {
88 if (se->elide)
89 continue;
90
91 gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
92 -1, se->se_header,
93 renderer, "text",
94 col_idx++, NULL);
95 }
96
97 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
98
99 g_object_unref(GTK_TREE_MODEL(store));
100
101 total_period = hists->stats.total_period;
102
103 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
104 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
105 GtkTreeIter iter;
106 double percent;
107 char s[512];
108
109 if (h->filtered)
110 continue;
111
112 gtk_list_store_append(store, &iter);
113
114 col_idx = 0;
115
116 percent = (h->period * 100.0) / total_period;
117
118 snprintf(s, ARRAY_SIZE(s), "%.2f", percent);
119
120 gtk_list_store_set(store, &iter, col_idx++, s, -1);
121
122 list_for_each_entry(se, &hist_entry__sort_list, list) {
123 if (se->elide)
124 continue;
125
126 se->se_snprintf(h, s, ARRAY_SIZE(s),
127 hists__col_len(hists, se->se_width_idx));
128
129 gtk_list_store_set(store, &iter, col_idx++, s, -1);
130 }
131 }
132
133 gtk_container_add(GTK_CONTAINER(window), view);
134}
135
136int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
137 const char *help __used,
138 void (*timer) (void *arg)__used,
139 void *arg __used, int delay_secs __used)
140{
141 struct perf_evsel *pos;
142 GtkWidget *notebook;
143 GtkWidget *window;
144
145 signal(SIGSEGV, perf_gtk_signal);
146 signal(SIGFPE, perf_gtk_signal);
147 signal(SIGINT, perf_gtk_signal);
148 signal(SIGQUIT, perf_gtk_signal);
149 signal(SIGTERM, perf_gtk_signal);
150
151 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
152
153 gtk_window_set_title(GTK_WINDOW(window), "perf report");
154
155 g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
156
157 notebook = gtk_notebook_new();
158
159 list_for_each_entry(pos, &evlist->entries, node) {
160 struct hists *hists = &pos->hists;
161 const char *evname = event_name(pos);
162 GtkWidget *scrolled_window;
163 GtkWidget *tab_label;
164
165 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
166
167 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
168 GTK_POLICY_AUTOMATIC,
169 GTK_POLICY_AUTOMATIC);
170
171 perf_gtk_show_hists(scrolled_window, hists);
172
173 tab_label = gtk_label_new(evname);
174
175 gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
176 }
177
178 gtk_container_add(GTK_CONTAINER(window), notebook);
179
180 gtk_widget_show_all(window);
181
182 perf_gtk_resize_window(window);
183
184 gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
185
186 gtk_main();
187
188 return 0;
189}
diff --git a/tools/perf/util/gtk/gtk.h b/tools/perf/util/gtk/gtk.h
deleted file mode 100644
index 75177ee04032..000000000000
--- a/tools/perf/util/gtk/gtk.h
+++ /dev/null
@@ -1,8 +0,0 @@
1#ifndef _PERF_GTK_H_
2#define _PERF_GTK_H_ 1
3
4#pragma GCC diagnostic ignored "-Wstrict-prototypes"
5#include <gtk/gtk.h>
6#pragma GCC diagnostic error "-Wstrict-prototypes"
7
8#endif /* _PERF_GTK_H_ */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 4c7c2d73251f..e909d43cf542 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -31,21 +31,16 @@ static const char **header_argv;
31 31
32int perf_header__push_event(u64 id, const char *name) 32int perf_header__push_event(u64 id, const char *name)
33{ 33{
34 struct perf_trace_event_type *nevents;
35
34 if (strlen(name) > MAX_EVENT_NAME) 36 if (strlen(name) > MAX_EVENT_NAME)
35 pr_warning("Event %s will be truncated\n", name); 37 pr_warning("Event %s will be truncated\n", name);
36 38
37 if (!events) { 39 nevents = realloc(events, (event_count + 1) * sizeof(*events));
38 events = malloc(sizeof(struct perf_trace_event_type)); 40 if (nevents == NULL)
39 if (events == NULL) 41 return -ENOMEM;
40 return -ENOMEM; 42 events = nevents;
41 } else {
42 struct perf_trace_event_type *nevents;
43 43
44 nevents = realloc(events, (event_count + 1) * sizeof(*events));
45 if (nevents == NULL)
46 return -ENOMEM;
47 events = nevents;
48 }
49 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); 44 memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
50 events[event_count].event_id = id; 45 events[event_count].event_id = id;
51 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); 46 strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
@@ -296,7 +291,7 @@ int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
296 if (mkdir_p(filename, 0755)) 291 if (mkdir_p(filename, 0755))
297 goto out_free; 292 goto out_free;
298 293
299 snprintf(filename + len, sizeof(filename) - len, "/%s", sbuild_id); 294 snprintf(filename + len, size - len, "/%s", sbuild_id);
300 295
301 if (access(filename, F_OK)) { 296 if (access(filename, F_OK)) {
302 if (is_kallsyms) { 297 if (is_kallsyms) {
@@ -442,7 +437,7 @@ static bool perf_session__read_build_ids(struct perf_session *session, bool with
442 return ret; 437 return ret;
443} 438}
444 439
445static int write_trace_info(int fd, struct perf_header *h __used, 440static int write_tracing_data(int fd, struct perf_header *h __used,
446 struct perf_evlist *evlist) 441 struct perf_evlist *evlist)
447{ 442{
448 return read_tracing_data(fd, &evlist->entries); 443 return read_tracing_data(fd, &evlist->entries);
@@ -1477,7 +1472,7 @@ out:
1477 return err; 1472 return err;
1478} 1473}
1479 1474
1480static int process_trace_info(struct perf_file_section *section __unused, 1475static int process_tracing_data(struct perf_file_section *section __unused,
1481 struct perf_header *ph __unused, 1476 struct perf_header *ph __unused,
1482 int feat __unused, int fd) 1477 int feat __unused, int fd)
1483{ 1478{
@@ -1513,11 +1508,11 @@ struct feature_ops {
1513 .full_only = true } 1508 .full_only = true }
1514 1509
1515/* feature_ops not implemented: */ 1510/* feature_ops not implemented: */
1516#define print_trace_info NULL 1511#define print_tracing_data NULL
1517#define print_build_id NULL 1512#define print_build_id NULL
1518 1513
1519static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { 1514static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1520 FEAT_OPP(HEADER_TRACE_INFO, trace_info), 1515 FEAT_OPP(HEADER_TRACING_DATA, tracing_data),
1521 FEAT_OPP(HEADER_BUILD_ID, build_id), 1516 FEAT_OPP(HEADER_BUILD_ID, build_id),
1522 FEAT_OPA(HEADER_HOSTNAME, hostname), 1517 FEAT_OPA(HEADER_HOSTNAME, hostname),
1523 FEAT_OPA(HEADER_OSRELEASE, osrelease), 1518 FEAT_OPA(HEADER_OSRELEASE, osrelease),
@@ -1947,7 +1942,6 @@ int perf_file_header__read(struct perf_file_header *header,
1947 else 1942 else
1948 return -1; 1943 return -1;
1949 } else if (ph->needs_swap) { 1944 } else if (ph->needs_swap) {
1950 unsigned int i;
1951 /* 1945 /*
1952 * feature bitmap is declared as an array of unsigned longs -- 1946 * feature bitmap is declared as an array of unsigned longs --
1953 * not good since its size can differ between the host that 1947 * not good since its size can differ between the host that
@@ -1963,14 +1957,17 @@ int perf_file_header__read(struct perf_file_header *header,
1963 * file), punt and fallback to the original behavior -- 1957 * file), punt and fallback to the original behavior --
1964 * clearing all feature bits and setting buildid. 1958 * clearing all feature bits and setting buildid.
1965 */ 1959 */
1966 for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i) 1960 mem_bswap_64(&header->adds_features,
1967 header->adds_features[i] = bswap_64(header->adds_features[i]); 1961 BITS_TO_U64(HEADER_FEAT_BITS));
1968 1962
1969 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { 1963 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
1970 for (i = 0; i < BITS_TO_LONGS(HEADER_FEAT_BITS); ++i) { 1964 /* unswap as u64 */
1971 header->adds_features[i] = bswap_64(header->adds_features[i]); 1965 mem_bswap_64(&header->adds_features,
1972 header->adds_features[i] = bswap_32(header->adds_features[i]); 1966 BITS_TO_U64(HEADER_FEAT_BITS));
1973 } 1967
1968 /* unswap as u32 */
1969 mem_bswap_32(&header->adds_features,
1970 BITS_TO_U32(HEADER_FEAT_BITS));
1974 } 1971 }
1975 1972
1976 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { 1973 if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
@@ -2096,6 +2093,35 @@ static int read_attr(int fd, struct perf_header *ph,
2096 return ret <= 0 ? -1 : 0; 2093 return ret <= 0 ? -1 : 0;
2097} 2094}
2098 2095
2096static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel)
2097{
2098 struct event_format *event = trace_find_event(evsel->attr.config);
2099 char bf[128];
2100
2101 if (event == NULL)
2102 return -1;
2103
2104 snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name);
2105 evsel->name = strdup(bf);
2106 if (event->name == NULL)
2107 return -1;
2108
2109 return 0;
2110}
2111
2112static int perf_evlist__set_tracepoint_names(struct perf_evlist *evlist)
2113{
2114 struct perf_evsel *pos;
2115
2116 list_for_each_entry(pos, &evlist->entries, node) {
2117 if (pos->attr.type == PERF_TYPE_TRACEPOINT &&
2118 perf_evsel__set_tracepoint_name(pos))
2119 return -1;
2120 }
2121
2122 return 0;
2123}
2124
2099int perf_session__read_header(struct perf_session *session, int fd) 2125int perf_session__read_header(struct perf_session *session, int fd)
2100{ 2126{
2101 struct perf_header *header = &session->header; 2127 struct perf_header *header = &session->header;
@@ -2177,6 +2203,9 @@ int perf_session__read_header(struct perf_session *session, int fd)
2177 2203
2178 lseek(fd, header->data_offset, SEEK_SET); 2204 lseek(fd, header->data_offset, SEEK_SET);
2179 2205
2206 if (perf_evlist__set_tracepoint_names(session->evlist))
2207 goto out_delete_evlist;
2208
2180 header->frozen = 1; 2209 header->frozen = 1;
2181 return 0; 2210 return 0;
2182out_errno: 2211out_errno:
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 21a6be09c129..2d42b3e1826f 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -12,7 +12,7 @@
12enum { 12enum {
13 HEADER_RESERVED = 0, /* always cleared */ 13 HEADER_RESERVED = 0, /* always cleared */
14 HEADER_FIRST_FEATURE = 1, 14 HEADER_FIRST_FEATURE = 1,
15 HEADER_TRACE_INFO = 1, 15 HEADER_TRACING_DATA = 1,
16 HEADER_BUILD_ID, 16 HEADER_BUILD_ID,
17 17
18 HEADER_HOSTNAME, 18 HEADER_HOSTNAME,
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 9f6d630d5316..514e2a4b367d 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -378,7 +378,7 @@ void hist_entry__free(struct hist_entry *he)
378 * collapse the histogram 378 * collapse the histogram
379 */ 379 */
380 380
381static bool hists__collapse_insert_entry(struct hists *hists, 381static bool hists__collapse_insert_entry(struct hists *hists __used,
382 struct rb_root *root, 382 struct rb_root *root,
383 struct hist_entry *he) 383 struct hist_entry *he)
384{ 384{
@@ -397,8 +397,9 @@ static bool hists__collapse_insert_entry(struct hists *hists,
397 iter->period += he->period; 397 iter->period += he->period;
398 iter->nr_events += he->nr_events; 398 iter->nr_events += he->nr_events;
399 if (symbol_conf.use_callchain) { 399 if (symbol_conf.use_callchain) {
400 callchain_cursor_reset(&hists->callchain_cursor); 400 callchain_cursor_reset(&callchain_cursor);
401 callchain_merge(&hists->callchain_cursor, iter->callchain, 401 callchain_merge(&callchain_cursor,
402 iter->callchain,
402 he->callchain); 403 he->callchain);
403 } 404 }
404 hist_entry__free(he); 405 hist_entry__free(he);
@@ -599,7 +600,7 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
599 if (chain->ms.sym) 600 if (chain->ms.sym)
600 ret += fprintf(fp, "%s\n", chain->ms.sym->name); 601 ret += fprintf(fp, "%s\n", chain->ms.sym->name);
601 else 602 else
602 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip); 603 ret += fprintf(fp, "0x%0" PRIx64 "\n", chain->ip);
603 604
604 return ret; 605 return ret;
605} 606}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 2cae9df40e04..34bb556d6219 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -67,8 +67,6 @@ struct hists {
67 struct events_stats stats; 67 struct events_stats stats;
68 u64 event_stream; 68 u64 event_stream;
69 u16 col_len[HISTC_NR_COLS]; 69 u16 col_len[HISTC_NR_COLS];
70 /* Best would be to reuse the session callchain cursor */
71 struct callchain_cursor callchain_cursor;
72}; 70};
73 71
74struct hist_entry *__hists__add_entry(struct hists *self, 72struct hist_entry *__hists__add_entry(struct hists *self,
@@ -138,7 +136,7 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
138#define K_LEFT -1 136#define K_LEFT -1
139#define K_RIGHT -2 137#define K_RIGHT -2
140#else 138#else
141#include "ui/keysyms.h" 139#include "../ui/keysyms.h"
142int hist_entry__tui_annotate(struct hist_entry *he, int evidx, 140int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
143 void(*timer)(void *arg), void *arg, int delay_secs); 141 void(*timer)(void *arg), void *arg, int delay_secs);
144 142
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index f1584833bd22..587a230d2075 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -8,6 +8,8 @@
8#define BITS_PER_LONG __WORDSIZE 8#define BITS_PER_LONG __WORDSIZE
9#define BITS_PER_BYTE 8 9#define BITS_PER_BYTE 8
10#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) 10#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
11#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
12#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
11 13
12#define for_each_set_bit(bit, addr, size) \ 14#define for_each_set_bit(bit, addr, size) \
13 for ((bit) = find_first_bit((addr), (size)); \ 15 for ((bit) = find_first_bit((addr), (size)); \
diff --git a/tools/perf/util/pager.c b/tools/perf/util/pager.c
index 1915de20dcac..3322b8446e89 100644
--- a/tools/perf/util/pager.c
+++ b/tools/perf/util/pager.c
@@ -57,6 +57,10 @@ void setup_pager(void)
57 } 57 }
58 if (!pager) 58 if (!pager)
59 pager = getenv("PAGER"); 59 pager = getenv("PAGER");
60 if (!pager) {
61 if (!access("/usr/bin/pager", X_OK))
62 pager = "/usr/bin/pager";
63 }
60 if (!pager) 64 if (!pager)
61 pager = "less"; 65 pager = "less";
62 else if (!*pager || !strcmp(pager, "cat")) 66 else if (!*pager || !strcmp(pager, "cat"))
diff --git a/tools/perf/util/parse-events-test.c b/tools/perf/util/parse-events-test.c
new file mode 100644
index 000000000000..76b98e2a587d
--- /dev/null
+++ b/tools/perf/util/parse-events-test.c
@@ -0,0 +1,625 @@
1
2#include "parse-events.h"
3#include "evsel.h"
4#include "evlist.h"
5#include "sysfs.h"
6#include "../../../include/linux/hw_breakpoint.h"
7
8#define TEST_ASSERT_VAL(text, cond) \
9do { \
10 if (!(cond)) { \
11 pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
12 return -1; \
13 } \
14} while (0)
15
16static int test__checkevent_tracepoint(struct perf_evlist *evlist)
17{
18 struct perf_evsel *evsel = list_entry(evlist->entries.next,
19 struct perf_evsel, node);
20
21 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
22 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
23 TEST_ASSERT_VAL("wrong sample_type",
24 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
25 evsel->attr.sample_type);
26 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
27 return 0;
28}
29
30static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
31{
32 struct perf_evsel *evsel;
33
34 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
35
36 list_for_each_entry(evsel, &evlist->entries, node) {
37 TEST_ASSERT_VAL("wrong type",
38 PERF_TYPE_TRACEPOINT == evsel->attr.type);
39 TEST_ASSERT_VAL("wrong sample_type",
40 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
41 == evsel->attr.sample_type);
42 TEST_ASSERT_VAL("wrong sample_period",
43 1 == evsel->attr.sample_period);
44 }
45 return 0;
46}
47
48static int test__checkevent_raw(struct perf_evlist *evlist)
49{
50 struct perf_evsel *evsel = list_entry(evlist->entries.next,
51 struct perf_evsel, node);
52
53 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
54 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
55 TEST_ASSERT_VAL("wrong config", 0x1a == evsel->attr.config);
56 return 0;
57}
58
59static int test__checkevent_numeric(struct perf_evlist *evlist)
60{
61 struct perf_evsel *evsel = list_entry(evlist->entries.next,
62 struct perf_evsel, node);
63
64 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
65 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
66 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
67 return 0;
68}
69
70static int test__checkevent_symbolic_name(struct perf_evlist *evlist)
71{
72 struct perf_evsel *evsel = list_entry(evlist->entries.next,
73 struct perf_evsel, node);
74
75 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
76 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
77 TEST_ASSERT_VAL("wrong config",
78 PERF_COUNT_HW_INSTRUCTIONS == evsel->attr.config);
79 return 0;
80}
81
82static int test__checkevent_symbolic_name_config(struct perf_evlist *evlist)
83{
84 struct perf_evsel *evsel = list_entry(evlist->entries.next,
85 struct perf_evsel, node);
86
87 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
88 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
89 TEST_ASSERT_VAL("wrong config",
90 PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
91 TEST_ASSERT_VAL("wrong period",
92 100000 == evsel->attr.sample_period);
93 TEST_ASSERT_VAL("wrong config1",
94 0 == evsel->attr.config1);
95 TEST_ASSERT_VAL("wrong config2",
96 1 == evsel->attr.config2);
97 return 0;
98}
99
100static int test__checkevent_symbolic_alias(struct perf_evlist *evlist)
101{
102 struct perf_evsel *evsel = list_entry(evlist->entries.next,
103 struct perf_evsel, node);
104
105 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
106 TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->attr.type);
107 TEST_ASSERT_VAL("wrong config",
108 PERF_COUNT_SW_PAGE_FAULTS == evsel->attr.config);
109 return 0;
110}
111
112static int test__checkevent_genhw(struct perf_evlist *evlist)
113{
114 struct perf_evsel *evsel = list_entry(evlist->entries.next,
115 struct perf_evsel, node);
116
117 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
118 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->attr.type);
119 TEST_ASSERT_VAL("wrong config", (1 << 16) == evsel->attr.config);
120 return 0;
121}
122
123static int test__checkevent_breakpoint(struct perf_evlist *evlist)
124{
125 struct perf_evsel *evsel = list_entry(evlist->entries.next,
126 struct perf_evsel, node);
127
128 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
129 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
130 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
131 TEST_ASSERT_VAL("wrong bp_type", (HW_BREAKPOINT_R | HW_BREAKPOINT_W) ==
132 evsel->attr.bp_type);
133 TEST_ASSERT_VAL("wrong bp_len", HW_BREAKPOINT_LEN_4 ==
134 evsel->attr.bp_len);
135 return 0;
136}
137
138static int test__checkevent_breakpoint_x(struct perf_evlist *evlist)
139{
140 struct perf_evsel *evsel = list_entry(evlist->entries.next,
141 struct perf_evsel, node);
142
143 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
144 TEST_ASSERT_VAL("wrong type", PERF_TYPE_BREAKPOINT == evsel->attr.type);
145 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
146 TEST_ASSERT_VAL("wrong bp_type",
147 HW_BREAKPOINT_X == evsel->attr.bp_type);
148 TEST_ASSERT_VAL("wrong bp_len", sizeof(long) == evsel->attr.bp_len);
149 return 0;
150}
151
152static int test__checkevent_breakpoint_r(struct perf_evlist *evlist)
153{
154 struct perf_evsel *evsel = list_entry(evlist->entries.next,
155 struct perf_evsel, node);
156
157 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
158 TEST_ASSERT_VAL("wrong type",
159 PERF_TYPE_BREAKPOINT == evsel->attr.type);
160 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
161 TEST_ASSERT_VAL("wrong bp_type",
162 HW_BREAKPOINT_R == evsel->attr.bp_type);
163 TEST_ASSERT_VAL("wrong bp_len",
164 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
165 return 0;
166}
167
168static int test__checkevent_breakpoint_w(struct perf_evlist *evlist)
169{
170 struct perf_evsel *evsel = list_entry(evlist->entries.next,
171 struct perf_evsel, node);
172
173 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
174 TEST_ASSERT_VAL("wrong type",
175 PERF_TYPE_BREAKPOINT == evsel->attr.type);
176 TEST_ASSERT_VAL("wrong config", 0 == evsel->attr.config);
177 TEST_ASSERT_VAL("wrong bp_type",
178 HW_BREAKPOINT_W == evsel->attr.bp_type);
179 TEST_ASSERT_VAL("wrong bp_len",
180 HW_BREAKPOINT_LEN_4 == evsel->attr.bp_len);
181 return 0;
182}
183
184static int test__checkevent_tracepoint_modifier(struct perf_evlist *evlist)
185{
186 struct perf_evsel *evsel = list_entry(evlist->entries.next,
187 struct perf_evsel, node);
188
189 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
190 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
191 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
192 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
193
194 return test__checkevent_tracepoint(evlist);
195}
196
197static int
198test__checkevent_tracepoint_multi_modifier(struct perf_evlist *evlist)
199{
200 struct perf_evsel *evsel;
201
202 TEST_ASSERT_VAL("wrong number of entries", evlist->nr_entries > 1);
203
204 list_for_each_entry(evsel, &evlist->entries, node) {
205 TEST_ASSERT_VAL("wrong exclude_user",
206 !evsel->attr.exclude_user);
207 TEST_ASSERT_VAL("wrong exclude_kernel",
208 evsel->attr.exclude_kernel);
209 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
210 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
211 }
212
213 return test__checkevent_tracepoint_multi(evlist);
214}
215
216static int test__checkevent_raw_modifier(struct perf_evlist *evlist)
217{
218 struct perf_evsel *evsel = list_entry(evlist->entries.next,
219 struct perf_evsel, node);
220
221 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
222 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
223 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
224 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
225
226 return test__checkevent_raw(evlist);
227}
228
229static int test__checkevent_numeric_modifier(struct perf_evlist *evlist)
230{
231 struct perf_evsel *evsel = list_entry(evlist->entries.next,
232 struct perf_evsel, node);
233
234 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
235 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
236 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
237 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
238
239 return test__checkevent_numeric(evlist);
240}
241
242static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)
243{
244 struct perf_evsel *evsel = list_entry(evlist->entries.next,
245 struct perf_evsel, node);
246
247 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
248 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
249 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
250 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
251
252 return test__checkevent_symbolic_name(evlist);
253}
254
255static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist)
256{
257 struct perf_evsel *evsel = list_entry(evlist->entries.next,
258 struct perf_evsel, node);
259
260 TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
261 TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
262
263 return test__checkevent_symbolic_name(evlist);
264}
265
266static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist)
267{
268 struct perf_evsel *evsel = list_entry(evlist->entries.next,
269 struct perf_evsel, node);
270
271 TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
272 TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
273
274 return test__checkevent_symbolic_name(evlist);
275}
276
277static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)
278{
279 struct perf_evsel *evsel = list_entry(evlist->entries.next,
280 struct perf_evsel, node);
281
282 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
283 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
284 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
285 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
286
287 return test__checkevent_symbolic_alias(evlist);
288}
289
290static int test__checkevent_genhw_modifier(struct perf_evlist *evlist)
291{
292 struct perf_evsel *evsel = list_entry(evlist->entries.next,
293 struct perf_evsel, node);
294
295 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
296 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
297 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
298 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
299
300 return test__checkevent_genhw(evlist);
301}
302
303static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist)
304{
305 struct perf_evsel *evsel = list_entry(evlist->entries.next,
306 struct perf_evsel, node);
307
308 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
309 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
310 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
311 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
312
313 return test__checkevent_breakpoint(evlist);
314}
315
316static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist)
317{
318 struct perf_evsel *evsel = list_entry(evlist->entries.next,
319 struct perf_evsel, node);
320
321 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
322 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
323 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
324 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
325
326 return test__checkevent_breakpoint_x(evlist);
327}
328
329static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist)
330{
331 struct perf_evsel *evsel = list_entry(evlist->entries.next,
332 struct perf_evsel, node);
333
334 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
335 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
336 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
337 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
338
339 return test__checkevent_breakpoint_r(evlist);
340}
341
342static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist)
343{
344 struct perf_evsel *evsel = list_entry(evlist->entries.next,
345 struct perf_evsel, node);
346
347 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
348 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
349 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
350 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
351
352 return test__checkevent_breakpoint_w(evlist);
353}
354
355static int test__checkevent_pmu(struct perf_evlist *evlist)
356{
357
358 struct perf_evsel *evsel = list_entry(evlist->entries.next,
359 struct perf_evsel, node);
360
361 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
362 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
363 TEST_ASSERT_VAL("wrong config", 10 == evsel->attr.config);
364 TEST_ASSERT_VAL("wrong config1", 1 == evsel->attr.config1);
365 TEST_ASSERT_VAL("wrong config2", 3 == evsel->attr.config2);
366 TEST_ASSERT_VAL("wrong period", 1000 == evsel->attr.sample_period);
367
368 return 0;
369}
370
371static int test__checkevent_list(struct perf_evlist *evlist)
372{
373 struct perf_evsel *evsel;
374
375 TEST_ASSERT_VAL("wrong number of entries", 3 == evlist->nr_entries);
376
377 /* r1 */
378 evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
379 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
380 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
381 TEST_ASSERT_VAL("wrong config1", 0 == evsel->attr.config1);
382 TEST_ASSERT_VAL("wrong config2", 0 == evsel->attr.config2);
383 TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
384 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
385 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
386 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
387
388 /* syscalls:sys_enter_open:k */
389 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
390 TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
391 TEST_ASSERT_VAL("wrong sample_type",
392 (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
393 evsel->attr.sample_type);
394 TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
395 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
396 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
397 TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
398 TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
399
400 /* 1:1:hp */
401 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
402 TEST_ASSERT_VAL("wrong type", 1 == evsel->attr.type);
403 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
404 TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
405 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
406 TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
407 TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip);
408
409 return 0;
410}
411
412static int test__checkevent_pmu_name(struct perf_evlist *evlist)
413{
414 struct perf_evsel *evsel;
415
416 /* cpu/config=1,name=krava1/u */
417 evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
418 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
419 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
420 TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
421 TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "krava"));
422
423 /* cpu/config=2/" */
424 evsel = list_entry(evsel->node.next, struct perf_evsel, node);
425 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
426 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
427 TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config);
428 TEST_ASSERT_VAL("wrong name", !strcmp(evsel->name, "raw 0x2"));
429
430 return 0;
431}
432
433struct test__event_st {
434 const char *name;
435 __u32 type;
436 int (*check)(struct perf_evlist *evlist);
437};
438
439static struct test__event_st test__events[] = {
440 [0] = {
441 .name = "syscalls:sys_enter_open",
442 .check = test__checkevent_tracepoint,
443 },
444 [1] = {
445 .name = "syscalls:*",
446 .check = test__checkevent_tracepoint_multi,
447 },
448 [2] = {
449 .name = "r1a",
450 .check = test__checkevent_raw,
451 },
452 [3] = {
453 .name = "1:1",
454 .check = test__checkevent_numeric,
455 },
456 [4] = {
457 .name = "instructions",
458 .check = test__checkevent_symbolic_name,
459 },
460 [5] = {
461 .name = "cycles/period=100000,config2/",
462 .check = test__checkevent_symbolic_name_config,
463 },
464 [6] = {
465 .name = "faults",
466 .check = test__checkevent_symbolic_alias,
467 },
468 [7] = {
469 .name = "L1-dcache-load-miss",
470 .check = test__checkevent_genhw,
471 },
472 [8] = {
473 .name = "mem:0",
474 .check = test__checkevent_breakpoint,
475 },
476 [9] = {
477 .name = "mem:0:x",
478 .check = test__checkevent_breakpoint_x,
479 },
480 [10] = {
481 .name = "mem:0:r",
482 .check = test__checkevent_breakpoint_r,
483 },
484 [11] = {
485 .name = "mem:0:w",
486 .check = test__checkevent_breakpoint_w,
487 },
488 [12] = {
489 .name = "syscalls:sys_enter_open:k",
490 .check = test__checkevent_tracepoint_modifier,
491 },
492 [13] = {
493 .name = "syscalls:*:u",
494 .check = test__checkevent_tracepoint_multi_modifier,
495 },
496 [14] = {
497 .name = "r1a:kp",
498 .check = test__checkevent_raw_modifier,
499 },
500 [15] = {
501 .name = "1:1:hp",
502 .check = test__checkevent_numeric_modifier,
503 },
504 [16] = {
505 .name = "instructions:h",
506 .check = test__checkevent_symbolic_name_modifier,
507 },
508 [17] = {
509 .name = "faults:u",
510 .check = test__checkevent_symbolic_alias_modifier,
511 },
512 [18] = {
513 .name = "L1-dcache-load-miss:kp",
514 .check = test__checkevent_genhw_modifier,
515 },
516 [19] = {
517 .name = "mem:0:u",
518 .check = test__checkevent_breakpoint_modifier,
519 },
520 [20] = {
521 .name = "mem:0:x:k",
522 .check = test__checkevent_breakpoint_x_modifier,
523 },
524 [21] = {
525 .name = "mem:0:r:hp",
526 .check = test__checkevent_breakpoint_r_modifier,
527 },
528 [22] = {
529 .name = "mem:0:w:up",
530 .check = test__checkevent_breakpoint_w_modifier,
531 },
532 [23] = {
533 .name = "r1,syscalls:sys_enter_open:k,1:1:hp",
534 .check = test__checkevent_list,
535 },
536 [24] = {
537 .name = "instructions:G",
538 .check = test__checkevent_exclude_host_modifier,
539 },
540 [25] = {
541 .name = "instructions:H",
542 .check = test__checkevent_exclude_guest_modifier,
543 },
544};
545
546#define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st))
547
548static struct test__event_st test__events_pmu[] = {
549 [0] = {
550 .name = "cpu/config=10,config1,config2=3,period=1000/u",
551 .check = test__checkevent_pmu,
552 },
553 [1] = {
554 .name = "cpu/config=1,name=krava/u,cpu/config=2/u",
555 .check = test__checkevent_pmu_name,
556 },
557};
558
559#define TEST__EVENTS_PMU_CNT (sizeof(test__events_pmu) / \
560 sizeof(struct test__event_st))
561
562static int test(struct test__event_st *e)
563{
564 struct perf_evlist *evlist;
565 int ret;
566
567 evlist = perf_evlist__new(NULL, NULL);
568 if (evlist == NULL)
569 return -ENOMEM;
570
571 ret = parse_events(evlist, e->name, 0);
572 if (ret) {
573 pr_debug("failed to parse event '%s', err %d\n",
574 e->name, ret);
575 return ret;
576 }
577
578 ret = e->check(evlist);
579 perf_evlist__delete(evlist);
580
581 return ret;
582}
583
584static int test_events(struct test__event_st *events, unsigned cnt)
585{
586 int ret = 0;
587 unsigned i;
588
589 for (i = 0; i < cnt; i++) {
590 struct test__event_st *e = &events[i];
591
592 pr_debug("running test %d '%s'\n", i, e->name);
593 ret = test(e);
594 if (ret)
595 break;
596 }
597
598 return ret;
599}
600
601static int test_pmu(void)
602{
603 struct stat st;
604 char path[PATH_MAX];
605 int ret;
606
607 snprintf(path, PATH_MAX, "%s/bus/event_source/devices/cpu/format/",
608 sysfs_find_mountpoint());
609
610 ret = stat(path, &st);
611 if (ret)
612 pr_debug("ommiting PMU cpu tests\n");
613 return !ret;
614}
615
616int parse_events__test(void)
617{
618 int ret;
619
620 ret = test_events(test__events, TEST__EVENTS_CNT);
621 if (!ret && test_pmu())
622 ret = test_events(test__events_pmu, TEST__EVENTS_PMU_CNT);
623
624 return ret;
625}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5b3a0ef4e232..05dbc8b3c767 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -23,8 +23,10 @@ struct event_symbol {
23 const char *alias; 23 const char *alias;
24}; 24};
25 25
26int parse_events_parse(struct list_head *list, struct list_head *list_tmp, 26#ifdef PARSER_DEBUG
27 int *idx); 27extern int parse_events_debug;
28#endif
29int parse_events_parse(struct list_head *list, int *idx);
28 30
29#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x 31#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
30#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x 32#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -60,19 +62,6 @@ static struct event_symbol event_symbols[] = {
60#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) 62#define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE)
61#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) 63#define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT)
62 64
63static const char *hw_event_names[PERF_COUNT_HW_MAX] = {
64 "cycles",
65 "instructions",
66 "cache-references",
67 "cache-misses",
68 "branches",
69 "branch-misses",
70 "bus-cycles",
71 "stalled-cycles-frontend",
72 "stalled-cycles-backend",
73 "ref-cycles",
74};
75
76static const char *sw_event_names[PERF_COUNT_SW_MAX] = { 65static const char *sw_event_names[PERF_COUNT_SW_MAX] = {
77 "cpu-clock", 66 "cpu-clock",
78 "task-clock", 67 "task-clock",
@@ -298,6 +287,16 @@ const char *event_name(struct perf_evsel *evsel)
298 u64 config = evsel->attr.config; 287 u64 config = evsel->attr.config;
299 int type = evsel->attr.type; 288 int type = evsel->attr.type;
300 289
290 if (type == PERF_TYPE_RAW || type == PERF_TYPE_HARDWARE) {
291 /*
292 * XXX minimal fix, see comment on perf_evsen__name, this static buffer
293 * will go away together with event_name in the next devel cycle.
294 */
295 static char bf[128];
296 perf_evsel__name(evsel, bf, sizeof(bf));
297 return bf;
298 }
299
301 if (evsel->name) 300 if (evsel->name)
302 return evsel->name; 301 return evsel->name;
303 302
@@ -315,9 +314,7 @@ const char *__event_name(int type, u64 config)
315 314
316 switch (type) { 315 switch (type) {
317 case PERF_TYPE_HARDWARE: 316 case PERF_TYPE_HARDWARE:
318 if (config < PERF_COUNT_HW_MAX && hw_event_names[config]) 317 return __perf_evsel__hw_name(config);
319 return hw_event_names[config];
320 return "unknown-hardware";
321 318
322 case PERF_TYPE_HW_CACHE: { 319 case PERF_TYPE_HW_CACHE: {
323 u8 cache_type, cache_op, cache_result; 320 u8 cache_type, cache_op, cache_result;
@@ -355,20 +352,30 @@ const char *__event_name(int type, u64 config)
355 return "unknown"; 352 return "unknown";
356} 353}
357 354
358static int add_event(struct list_head *list, int *idx, 355static int add_event(struct list_head **_list, int *idx,
359 struct perf_event_attr *attr, char *name) 356 struct perf_event_attr *attr, char *name)
360{ 357{
361 struct perf_evsel *evsel; 358 struct perf_evsel *evsel;
359 struct list_head *list = *_list;
360
361 if (!list) {
362 list = malloc(sizeof(*list));
363 if (!list)
364 return -ENOMEM;
365 INIT_LIST_HEAD(list);
366 }
362 367
363 event_attr_init(attr); 368 event_attr_init(attr);
364 369
365 evsel = perf_evsel__new(attr, (*idx)++); 370 evsel = perf_evsel__new(attr, (*idx)++);
366 if (!evsel) 371 if (!evsel) {
372 free(list);
367 return -ENOMEM; 373 return -ENOMEM;
368 374 }
369 list_add_tail(&evsel->node, list);
370 375
371 evsel->name = strdup(name); 376 evsel->name = strdup(name);
377 list_add_tail(&evsel->node, list);
378 *_list = list;
372 return 0; 379 return 0;
373} 380}
374 381
@@ -390,7 +397,7 @@ static int parse_aliases(char *str, const char *names[][MAX_ALIASES], int size)
390 return -1; 397 return -1;
391} 398}
392 399
393int parse_events_add_cache(struct list_head *list, int *idx, 400int parse_events_add_cache(struct list_head **list, int *idx,
394 char *type, char *op_result1, char *op_result2) 401 char *type, char *op_result1, char *op_result2)
395{ 402{
396 struct perf_event_attr attr; 403 struct perf_event_attr attr;
@@ -451,7 +458,7 @@ int parse_events_add_cache(struct list_head *list, int *idx,
451 return add_event(list, idx, &attr, name); 458 return add_event(list, idx, &attr, name);
452} 459}
453 460
454static int add_tracepoint(struct list_head *list, int *idx, 461static int add_tracepoint(struct list_head **list, int *idx,
455 char *sys_name, char *evt_name) 462 char *sys_name, char *evt_name)
456{ 463{
457 struct perf_event_attr attr; 464 struct perf_event_attr attr;
@@ -488,7 +495,7 @@ static int add_tracepoint(struct list_head *list, int *idx,
488 return add_event(list, idx, &attr, name); 495 return add_event(list, idx, &attr, name);
489} 496}
490 497
491static int add_tracepoint_multi(struct list_head *list, int *idx, 498static int add_tracepoint_multi(struct list_head **list, int *idx,
492 char *sys_name, char *evt_name) 499 char *sys_name, char *evt_name)
493{ 500{
494 char evt_path[MAXPATHLEN]; 501 char evt_path[MAXPATHLEN];
@@ -519,7 +526,7 @@ static int add_tracepoint_multi(struct list_head *list, int *idx,
519 return ret; 526 return ret;
520} 527}
521 528
522int parse_events_add_tracepoint(struct list_head *list, int *idx, 529int parse_events_add_tracepoint(struct list_head **list, int *idx,
523 char *sys, char *event) 530 char *sys, char *event)
524{ 531{
525 int ret; 532 int ret;
@@ -563,7 +570,7 @@ parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
563 return 0; 570 return 0;
564} 571}
565 572
566int parse_events_add_breakpoint(struct list_head *list, int *idx, 573int parse_events_add_breakpoint(struct list_head **list, int *idx,
567 void *ptr, char *type) 574 void *ptr, char *type)
568{ 575{
569 struct perf_event_attr attr; 576 struct perf_event_attr attr;
@@ -593,17 +600,27 @@ int parse_events_add_breakpoint(struct list_head *list, int *idx,
593static int config_term(struct perf_event_attr *attr, 600static int config_term(struct perf_event_attr *attr,
594 struct parse_events__term *term) 601 struct parse_events__term *term)
595{ 602{
596 switch (term->type) { 603#define CHECK_TYPE_VAL(type) \
604do { \
605 if (PARSE_EVENTS__TERM_TYPE_ ## type != term->type_val) \
606 return -EINVAL; \
607} while (0)
608
609 switch (term->type_term) {
597 case PARSE_EVENTS__TERM_TYPE_CONFIG: 610 case PARSE_EVENTS__TERM_TYPE_CONFIG:
611 CHECK_TYPE_VAL(NUM);
598 attr->config = term->val.num; 612 attr->config = term->val.num;
599 break; 613 break;
600 case PARSE_EVENTS__TERM_TYPE_CONFIG1: 614 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
615 CHECK_TYPE_VAL(NUM);
601 attr->config1 = term->val.num; 616 attr->config1 = term->val.num;
602 break; 617 break;
603 case PARSE_EVENTS__TERM_TYPE_CONFIG2: 618 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
619 CHECK_TYPE_VAL(NUM);
604 attr->config2 = term->val.num; 620 attr->config2 = term->val.num;
605 break; 621 break;
606 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD: 622 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
623 CHECK_TYPE_VAL(NUM);
607 attr->sample_period = term->val.num; 624 attr->sample_period = term->val.num;
608 break; 625 break;
609 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE: 626 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
@@ -612,10 +629,15 @@ static int config_term(struct perf_event_attr *attr,
612 * attr->branch_sample_type = term->val.num; 629 * attr->branch_sample_type = term->val.num;
613 */ 630 */
614 break; 631 break;
632 case PARSE_EVENTS__TERM_TYPE_NAME:
633 CHECK_TYPE_VAL(STR);
634 break;
615 default: 635 default:
616 return -EINVAL; 636 return -EINVAL;
617 } 637 }
638
618 return 0; 639 return 0;
640#undef CHECK_TYPE_VAL
619} 641}
620 642
621static int config_attr(struct perf_event_attr *attr, 643static int config_attr(struct perf_event_attr *attr,
@@ -630,7 +652,7 @@ static int config_attr(struct perf_event_attr *attr,
630 return 0; 652 return 0;
631} 653}
632 654
633int parse_events_add_numeric(struct list_head *list, int *idx, 655int parse_events_add_numeric(struct list_head **list, int *idx,
634 unsigned long type, unsigned long config, 656 unsigned long type, unsigned long config,
635 struct list_head *head_config) 657 struct list_head *head_config)
636{ 658{
@@ -648,7 +670,24 @@ int parse_events_add_numeric(struct list_head *list, int *idx,
648 (char *) __event_name(type, config)); 670 (char *) __event_name(type, config));
649} 671}
650 672
651int parse_events_add_pmu(struct list_head *list, int *idx, 673static int parse_events__is_name_term(struct parse_events__term *term)
674{
675 return term->type_term == PARSE_EVENTS__TERM_TYPE_NAME;
676}
677
678static char *pmu_event_name(struct perf_event_attr *attr,
679 struct list_head *head_terms)
680{
681 struct parse_events__term *term;
682
683 list_for_each_entry(term, head_terms, list)
684 if (parse_events__is_name_term(term))
685 return term->val.str;
686
687 return (char *) __event_name(PERF_TYPE_RAW, attr->config);
688}
689
690int parse_events_add_pmu(struct list_head **list, int *idx,
652 char *name, struct list_head *head_config) 691 char *name, struct list_head *head_config)
653{ 692{
654 struct perf_event_attr attr; 693 struct perf_event_attr attr;
@@ -669,7 +708,8 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
669 if (perf_pmu__config(pmu, &attr, head_config)) 708 if (perf_pmu__config(pmu, &attr, head_config))
670 return -EINVAL; 709 return -EINVAL;
671 710
672 return add_event(list, idx, &attr, (char *) "pmu"); 711 return add_event(list, idx, &attr,
712 pmu_event_name(&attr, head_config));
673} 713}
674 714
675void parse_events_update_lists(struct list_head *list_event, 715void parse_events_update_lists(struct list_head *list_event,
@@ -681,7 +721,7 @@ void parse_events_update_lists(struct list_head *list_event,
681 * list, for next event definition. 721 * list, for next event definition.
682 */ 722 */
683 list_splice_tail(list_event, list_all); 723 list_splice_tail(list_event, list_all);
684 INIT_LIST_HEAD(list_event); 724 free(list_event);
685} 725}
686 726
687int parse_events_modifier(struct list_head *list, char *str) 727int parse_events_modifier(struct list_head *list, char *str)
@@ -756,10 +796,14 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
756 796
757 buffer = parse_events__scan_string(str); 797 buffer = parse_events__scan_string(str);
758 798
759 ret = parse_events_parse(&list, &list_tmp, &idx); 799#ifdef PARSER_DEBUG
800 parse_events_debug = 1;
801#endif
802 ret = parse_events_parse(&list, &idx);
760 803
761 parse_events__flush_buffer(buffer); 804 parse_events__flush_buffer(buffer);
762 parse_events__delete_buffer(buffer); 805 parse_events__delete_buffer(buffer);
806 parse_events_lex_destroy();
763 807
764 if (!ret) { 808 if (!ret) {
765 int entries = idx - evlist->nr_entries; 809 int entries = idx - evlist->nr_entries;
@@ -1015,11 +1059,12 @@ void print_events(const char *event_glob)
1015 1059
1016int parse_events__is_hardcoded_term(struct parse_events__term *term) 1060int parse_events__is_hardcoded_term(struct parse_events__term *term)
1017{ 1061{
1018 return term->type <= PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX; 1062 return term->type_term != PARSE_EVENTS__TERM_TYPE_USER;
1019} 1063}
1020 1064
1021int parse_events__new_term(struct parse_events__term **_term, int type, 1065static int new_term(struct parse_events__term **_term, int type_val,
1022 char *config, char *str, long num) 1066 int type_term, char *config,
1067 char *str, long num)
1023{ 1068{
1024 struct parse_events__term *term; 1069 struct parse_events__term *term;
1025 1070
@@ -1028,15 +1073,11 @@ int parse_events__new_term(struct parse_events__term **_term, int type,
1028 return -ENOMEM; 1073 return -ENOMEM;
1029 1074
1030 INIT_LIST_HEAD(&term->list); 1075 INIT_LIST_HEAD(&term->list);
1031 term->type = type; 1076 term->type_val = type_val;
1077 term->type_term = type_term;
1032 term->config = config; 1078 term->config = config;
1033 1079
1034 switch (type) { 1080 switch (type_val) {
1035 case PARSE_EVENTS__TERM_TYPE_CONFIG:
1036 case PARSE_EVENTS__TERM_TYPE_CONFIG1:
1037 case PARSE_EVENTS__TERM_TYPE_CONFIG2:
1038 case PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD:
1039 case PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE:
1040 case PARSE_EVENTS__TERM_TYPE_NUM: 1081 case PARSE_EVENTS__TERM_TYPE_NUM:
1041 term->val.num = num; 1082 term->val.num = num;
1042 break; 1083 break;
@@ -1051,6 +1092,20 @@ int parse_events__new_term(struct parse_events__term **_term, int type,
1051 return 0; 1092 return 0;
1052} 1093}
1053 1094
1095int parse_events__term_num(struct parse_events__term **term,
1096 int type_term, char *config, long num)
1097{
1098 return new_term(term, PARSE_EVENTS__TERM_TYPE_NUM, type_term,
1099 config, NULL, num);
1100}
1101
1102int parse_events__term_str(struct parse_events__term **term,
1103 int type_term, char *config, char *str)
1104{
1105 return new_term(term, PARSE_EVENTS__TERM_TYPE_STR, type_term,
1106 config, str, 0);
1107}
1108
1054void parse_events__free_terms(struct list_head *terms) 1109void parse_events__free_terms(struct list_head *terms)
1055{ 1110{
1056 struct parse_events__term *term, *h; 1111 struct parse_events__term *term, *h;
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index ca069f893381..8cac57ab4ee6 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -4,7 +4,11 @@
4 * Parse symbolic events/counts passed in as options: 4 * Parse symbolic events/counts passed in as options:
5 */ 5 */
6 6
7#include <linux/list.h>
8#include <stdbool.h>
9#include "types.h"
7#include "../../../include/linux/perf_event.h" 10#include "../../../include/linux/perf_event.h"
11#include "types.h"
8 12
9struct list_head; 13struct list_head;
10struct perf_evsel; 14struct perf_evsel;
@@ -34,16 +38,18 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
34#define EVENTS_HELP_MAX (128*1024) 38#define EVENTS_HELP_MAX (128*1024)
35 39
36enum { 40enum {
41 PARSE_EVENTS__TERM_TYPE_NUM,
42 PARSE_EVENTS__TERM_TYPE_STR,
43};
44
45enum {
46 PARSE_EVENTS__TERM_TYPE_USER,
37 PARSE_EVENTS__TERM_TYPE_CONFIG, 47 PARSE_EVENTS__TERM_TYPE_CONFIG,
38 PARSE_EVENTS__TERM_TYPE_CONFIG1, 48 PARSE_EVENTS__TERM_TYPE_CONFIG1,
39 PARSE_EVENTS__TERM_TYPE_CONFIG2, 49 PARSE_EVENTS__TERM_TYPE_CONFIG2,
50 PARSE_EVENTS__TERM_TYPE_NAME,
40 PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD, 51 PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD,
41 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE, 52 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
42 PARSE_EVENTS__TERM_TYPE_NUM,
43 PARSE_EVENTS__TERM_TYPE_STR,
44
45 PARSE_EVENTS__TERM_TYPE_HARDCODED_MAX =
46 PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE,
47}; 53};
48 54
49struct parse_events__term { 55struct parse_events__term {
@@ -52,35 +58,34 @@ struct parse_events__term {
52 char *str; 58 char *str;
53 long num; 59 long num;
54 } val; 60 } val;
55 int type; 61 int type_val;
56 62 int type_term;
57 struct list_head list; 63 struct list_head list;
58}; 64};
59 65
60int parse_events__is_hardcoded_term(struct parse_events__term *term); 66int parse_events__is_hardcoded_term(struct parse_events__term *term);
61int parse_events__new_term(struct parse_events__term **term, int type, 67int parse_events__term_num(struct parse_events__term **_term,
62 char *config, char *str, long num); 68 int type_term, char *config, long num);
69int parse_events__term_str(struct parse_events__term **_term,
70 int type_term, char *config, char *str);
63void parse_events__free_terms(struct list_head *terms); 71void parse_events__free_terms(struct list_head *terms);
64int parse_events_modifier(struct list_head *list __used, char *str __used); 72int parse_events_modifier(struct list_head *list, char *str);
65int parse_events_add_tracepoint(struct list_head *list, int *idx, 73int parse_events_add_tracepoint(struct list_head **list, int *idx,
66 char *sys, char *event); 74 char *sys, char *event);
67int parse_events_add_raw(struct perf_evlist *evlist, unsigned long config, 75int parse_events_add_numeric(struct list_head **list, int *idx,
68 unsigned long config1, unsigned long config2,
69 char *mod);
70int parse_events_add_numeric(struct list_head *list, int *idx,
71 unsigned long type, unsigned long config, 76 unsigned long type, unsigned long config,
72 struct list_head *head_config); 77 struct list_head *head_config);
73int parse_events_add_cache(struct list_head *list, int *idx, 78int parse_events_add_cache(struct list_head **list, int *idx,
74 char *type, char *op_result1, char *op_result2); 79 char *type, char *op_result1, char *op_result2);
75int parse_events_add_breakpoint(struct list_head *list, int *idx, 80int parse_events_add_breakpoint(struct list_head **list, int *idx,
76 void *ptr, char *type); 81 void *ptr, char *type);
77int parse_events_add_pmu(struct list_head *list, int *idx, 82int parse_events_add_pmu(struct list_head **list, int *idx,
78 char *pmu , struct list_head *head_config); 83 char *pmu , struct list_head *head_config);
79void parse_events_update_lists(struct list_head *list_event, 84void parse_events_update_lists(struct list_head *list_event,
80 struct list_head *list_all); 85 struct list_head *list_all);
81void parse_events_error(struct list_head *list_all, 86void parse_events_error(struct list_head *list_all,
82 struct list_head *list_event,
83 int *idx, char const *msg); 87 int *idx, char const *msg);
88int parse_events__test(void);
84 89
85void print_events(const char *event_glob); 90void print_events(const char *event_glob);
86void print_events_type(u8 type); 91void print_events_type(u8 type);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 05d766e3ecb5..618a8e788399 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -1,5 +1,6 @@
1 1
2%option prefix="parse_events_" 2%option prefix="parse_events_"
3%option stack
3 4
4%{ 5%{
5#include <errno.h> 6#include <errno.h>
@@ -50,11 +51,13 @@ static int term(int type)
50 51
51%} 52%}
52 53
54%x mem
55
53num_dec [0-9]+ 56num_dec [0-9]+
54num_hex 0x[a-fA-F0-9]+ 57num_hex 0x[a-fA-F0-9]+
55num_raw_hex [a-fA-F0-9]+ 58num_raw_hex [a-fA-F0-9]+
56name [a-zA-Z_*?][a-zA-Z0-9_*?]* 59name [a-zA-Z_*?][a-zA-Z0-9_*?]*
57modifier_event [ukhp]{1,5} 60modifier_event [ukhpGH]{1,8}
58modifier_bp [rwx] 61modifier_bp [rwx]
59 62
60%% 63%%
@@ -102,16 +105,16 @@ misses|miss { return str(PE_NAME_CACHE_OP_RESULT); }
102config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); } 105config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
103config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); } 106config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
104config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); } 107config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
108name { return term(PARSE_EVENTS__TERM_TYPE_NAME); }
105period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } 109period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
106branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } 110branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
107 111
108mem: { return PE_PREFIX_MEM; } 112mem: { BEGIN(mem); return PE_PREFIX_MEM; }
109r{num_raw_hex} { return raw(); } 113r{num_raw_hex} { return raw(); }
110{num_dec} { return value(10); } 114{num_dec} { return value(10); }
111{num_hex} { return value(16); } 115{num_hex} { return value(16); }
112 116
113{modifier_event} { return str(PE_MODIFIER_EVENT); } 117{modifier_event} { return str(PE_MODIFIER_EVENT); }
114{modifier_bp} { return str(PE_MODIFIER_BP); }
115{name} { return str(PE_NAME); } 118{name} { return str(PE_NAME); }
116"/" { return '/'; } 119"/" { return '/'; }
117- { return '-'; } 120- { return '-'; }
@@ -119,6 +122,25 @@ r{num_raw_hex} { return raw(); }
119: { return ':'; } 122: { return ':'; }
120= { return '='; } 123= { return '='; }
121 124
125<mem>{
126{modifier_bp} { return str(PE_MODIFIER_BP); }
127: { return ':'; }
128{num_dec} { return value(10); }
129{num_hex} { return value(16); }
130 /*
131 * We need to separate 'mem:' scanner part, in order to get specific
132 * modifier bits parsed out. Otherwise we would need to handle PE_NAME
133 * and we'd need to parse it manually. During the escape from <mem>
134 * state we need to put the escaping char back, so we dont miss it.
135 */
136. { unput(*parse_events_text); BEGIN(INITIAL); }
137 /*
138 * We destroy the scanner after reaching EOF,
139 * but anyway just to be sure get back to INIT state.
140 */
141<<EOF>> { BEGIN(INITIAL); }
142}
143
122%% 144%%
123 145
124int parse_events_wrap(void) 146int parse_events_wrap(void)
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index d9637da7333c..362cc59332ae 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -1,7 +1,6 @@
1 1
2%name-prefix "parse_events_" 2%name-prefix "parse_events_"
3%parse-param {struct list_head *list_all} 3%parse-param {struct list_head *list_all}
4%parse-param {struct list_head *list_event}
5%parse-param {int *idx} 4%parse-param {int *idx}
6 5
7%{ 6%{
@@ -41,6 +40,14 @@ do { \
41%type <str> PE_MODIFIER_BP 40%type <str> PE_MODIFIER_BP
42%type <head> event_config 41%type <head> event_config
43%type <term> event_term 42%type <term> event_term
43%type <head> event_pmu
44%type <head> event_legacy_symbol
45%type <head> event_legacy_cache
46%type <head> event_legacy_mem
47%type <head> event_legacy_tracepoint
48%type <head> event_legacy_numeric
49%type <head> event_legacy_raw
50%type <head> event_def
44 51
45%union 52%union
46{ 53{
@@ -62,13 +69,13 @@ event_def PE_MODIFIER_EVENT
62 * (there could be more events added for multiple tracepoint 69 * (there could be more events added for multiple tracepoint
63 * definitions via '*?'. 70 * definitions via '*?'.
64 */ 71 */
65 ABORT_ON(parse_events_modifier(list_event, $2)); 72 ABORT_ON(parse_events_modifier($1, $2));
66 parse_events_update_lists(list_event, list_all); 73 parse_events_update_lists($1, list_all);
67} 74}
68| 75|
69event_def 76event_def
70{ 77{
71 parse_events_update_lists(list_event, list_all); 78 parse_events_update_lists($1, list_all);
72} 79}
73 80
74event_def: event_pmu | 81event_def: event_pmu |
@@ -82,71 +89,102 @@ event_def: event_pmu |
82event_pmu: 89event_pmu:
83PE_NAME '/' event_config '/' 90PE_NAME '/' event_config '/'
84{ 91{
85 ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3)); 92 struct list_head *list = NULL;
93
94 ABORT_ON(parse_events_add_pmu(&list, idx, $1, $3));
86 parse_events__free_terms($3); 95 parse_events__free_terms($3);
96 $$ = list;
87} 97}
88 98
89event_legacy_symbol: 99event_legacy_symbol:
90PE_VALUE_SYM '/' event_config '/' 100PE_VALUE_SYM '/' event_config '/'
91{ 101{
102 struct list_head *list = NULL;
92 int type = $1 >> 16; 103 int type = $1 >> 16;
93 int config = $1 & 255; 104 int config = $1 & 255;
94 105
95 ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, $3)); 106 ABORT_ON(parse_events_add_numeric(&list, idx, type, config, $3));
96 parse_events__free_terms($3); 107 parse_events__free_terms($3);
108 $$ = list;
97} 109}
98| 110|
99PE_VALUE_SYM sep_slash_dc 111PE_VALUE_SYM sep_slash_dc
100{ 112{
113 struct list_head *list = NULL;
101 int type = $1 >> 16; 114 int type = $1 >> 16;
102 int config = $1 & 255; 115 int config = $1 & 255;
103 116
104 ABORT_ON(parse_events_add_numeric(list_event, idx, type, config, NULL)); 117 ABORT_ON(parse_events_add_numeric(&list, idx, type, config, NULL));
118 $$ = list;
105} 119}
106 120
107event_legacy_cache: 121event_legacy_cache:
108PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT 122PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
109{ 123{
110 ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, $5)); 124 struct list_head *list = NULL;
125
126 ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, $5));
127 $$ = list;
111} 128}
112| 129|
113PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT 130PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
114{ 131{
115 ABORT_ON(parse_events_add_cache(list_event, idx, $1, $3, NULL)); 132 struct list_head *list = NULL;
133
134 ABORT_ON(parse_events_add_cache(&list, idx, $1, $3, NULL));
135 $$ = list;
116} 136}
117| 137|
118PE_NAME_CACHE_TYPE 138PE_NAME_CACHE_TYPE
119{ 139{
120 ABORT_ON(parse_events_add_cache(list_event, idx, $1, NULL, NULL)); 140 struct list_head *list = NULL;
141
142 ABORT_ON(parse_events_add_cache(&list, idx, $1, NULL, NULL));
143 $$ = list;
121} 144}
122 145
123event_legacy_mem: 146event_legacy_mem:
124PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc 147PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
125{ 148{
126 ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, $4)); 149 struct list_head *list = NULL;
150
151 ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, $4));
152 $$ = list;
127} 153}
128| 154|
129PE_PREFIX_MEM PE_VALUE sep_dc 155PE_PREFIX_MEM PE_VALUE sep_dc
130{ 156{
131 ABORT_ON(parse_events_add_breakpoint(list_event, idx, (void *) $2, NULL)); 157 struct list_head *list = NULL;
158
159 ABORT_ON(parse_events_add_breakpoint(&list, idx, (void *) $2, NULL));
160 $$ = list;
132} 161}
133 162
134event_legacy_tracepoint: 163event_legacy_tracepoint:
135PE_NAME ':' PE_NAME 164PE_NAME ':' PE_NAME
136{ 165{
137 ABORT_ON(parse_events_add_tracepoint(list_event, idx, $1, $3)); 166 struct list_head *list = NULL;
167
168 ABORT_ON(parse_events_add_tracepoint(&list, idx, $1, $3));
169 $$ = list;
138} 170}
139 171
140event_legacy_numeric: 172event_legacy_numeric:
141PE_VALUE ':' PE_VALUE 173PE_VALUE ':' PE_VALUE
142{ 174{
143 ABORT_ON(parse_events_add_numeric(list_event, idx, $1, $3, NULL)); 175 struct list_head *list = NULL;
176
177 ABORT_ON(parse_events_add_numeric(&list, idx, $1, $3, NULL));
178 $$ = list;
144} 179}
145 180
146event_legacy_raw: 181event_legacy_raw:
147PE_RAW 182PE_RAW
148{ 183{
149 ABORT_ON(parse_events_add_numeric(list_event, idx, PERF_TYPE_RAW, $1, NULL)); 184 struct list_head *list = NULL;
185
186 ABORT_ON(parse_events_add_numeric(&list, idx, PERF_TYPE_RAW, $1, NULL));
187 $$ = list;
150} 188}
151 189
152event_config: 190event_config:
@@ -176,8 +214,8 @@ PE_NAME '=' PE_NAME
176{ 214{
177 struct parse_events__term *term; 215 struct parse_events__term *term;
178 216
179 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR, 217 ABORT_ON(parse_events__term_str(&term, PARSE_EVENTS__TERM_TYPE_USER,
180 $1, $3, 0)); 218 $1, $3));
181 $$ = term; 219 $$ = term;
182} 220}
183| 221|
@@ -185,8 +223,8 @@ PE_NAME '=' PE_VALUE
185{ 223{
186 struct parse_events__term *term; 224 struct parse_events__term *term;
187 225
188 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM, 226 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
189 $1, NULL, $3)); 227 $1, $3));
190 $$ = term; 228 $$ = term;
191} 229}
192| 230|
@@ -194,8 +232,16 @@ PE_NAME
194{ 232{
195 struct parse_events__term *term; 233 struct parse_events__term *term;
196 234
197 ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM, 235 ABORT_ON(parse_events__term_num(&term, PARSE_EVENTS__TERM_TYPE_USER,
198 $1, NULL, 1)); 236 $1, 1));
237 $$ = term;
238}
239|
240PE_TERM '=' PE_NAME
241{
242 struct parse_events__term *term;
243
244 ABORT_ON(parse_events__term_str(&term, $1, NULL, $3));
199 $$ = term; 245 $$ = term;
200} 246}
201| 247|
@@ -203,7 +249,7 @@ PE_TERM '=' PE_VALUE
203{ 249{
204 struct parse_events__term *term; 250 struct parse_events__term *term;
205 251
206 ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, $3)); 252 ABORT_ON(parse_events__term_num(&term, $1, NULL, $3));
207 $$ = term; 253 $$ = term;
208} 254}
209| 255|
@@ -211,7 +257,7 @@ PE_TERM
211{ 257{
212 struct parse_events__term *term; 258 struct parse_events__term *term;
213 259
214 ABORT_ON(parse_events__new_term(&term, $1, NULL, NULL, 1)); 260 ABORT_ON(parse_events__term_num(&term, $1, NULL, 1));
215 $$ = term; 261 $$ = term;
216} 262}
217 263
@@ -222,7 +268,6 @@ sep_slash_dc: '/' | ':' |
222%% 268%%
223 269
224void parse_events_error(struct list_head *list_all __used, 270void parse_events_error(struct list_head *list_all __used,
225 struct list_head *list_event __used,
226 int *idx __used, 271 int *idx __used,
227 char const *msg __used) 272 char const *msg __used)
228{ 273{
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index cb08a118e811..a119a5371699 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -225,7 +225,7 @@ static int pmu_config_term(struct list_head *formats,
225 if (parse_events__is_hardcoded_term(term)) 225 if (parse_events__is_hardcoded_term(term))
226 return 0; 226 return 0;
227 227
228 if (term->type != PARSE_EVENTS__TERM_TYPE_NUM) 228 if (term->type_val != PARSE_EVENTS__TERM_TYPE_NUM)
229 return -EINVAL; 229 return -EINVAL;
230 230
231 format = pmu_find_format(formats, term->config); 231 format = pmu_find_format(formats, term->config);
@@ -246,6 +246,11 @@ static int pmu_config_term(struct list_head *formats,
246 return -EINVAL; 246 return -EINVAL;
247 } 247 }
248 248
249 /*
250 * XXX If we ever decide to go with string values for
251 * non-hardcoded terms, here's the place to translate
252 * them into value.
253 */
249 *vp |= pmu_format_value(format->bits, term->val.num); 254 *vp |= pmu_format_value(format->bits, term->val.num);
250 return 0; 255 return 0;
251} 256}
@@ -253,9 +258,9 @@ static int pmu_config_term(struct list_head *formats,
253static int pmu_config(struct list_head *formats, struct perf_event_attr *attr, 258static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
254 struct list_head *head_terms) 259 struct list_head *head_terms)
255{ 260{
256 struct parse_events__term *term, *h; 261 struct parse_events__term *term;
257 262
258 list_for_each_entry_safe(term, h, head_terms, list) 263 list_for_each_entry(term, head_terms, list)
259 if (pmu_config_term(formats, attr, term)) 264 if (pmu_config_term(formats, attr, term))
260 return -EINVAL; 265 return -EINVAL;
261 266
@@ -324,49 +329,58 @@ static struct test_format {
324/* Simulated users input. */ 329/* Simulated users input. */
325static struct parse_events__term test_terms[] = { 330static struct parse_events__term test_terms[] = {
326 { 331 {
327 .config = (char *) "krava01", 332 .config = (char *) "krava01",
328 .val.num = 15, 333 .val.num = 15,
329 .type = PARSE_EVENTS__TERM_TYPE_NUM, 334 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
335 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
330 }, 336 },
331 { 337 {
332 .config = (char *) "krava02", 338 .config = (char *) "krava02",
333 .val.num = 170, 339 .val.num = 170,
334 .type = PARSE_EVENTS__TERM_TYPE_NUM, 340 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
341 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
335 }, 342 },
336 { 343 {
337 .config = (char *) "krava03", 344 .config = (char *) "krava03",
338 .val.num = 1, 345 .val.num = 1,
339 .type = PARSE_EVENTS__TERM_TYPE_NUM, 346 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
347 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
340 }, 348 },
341 { 349 {
342 .config = (char *) "krava11", 350 .config = (char *) "krava11",
343 .val.num = 27, 351 .val.num = 27,
344 .type = PARSE_EVENTS__TERM_TYPE_NUM, 352 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
353 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
345 }, 354 },
346 { 355 {
347 .config = (char *) "krava12", 356 .config = (char *) "krava12",
348 .val.num = 1, 357 .val.num = 1,
349 .type = PARSE_EVENTS__TERM_TYPE_NUM, 358 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
359 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
350 }, 360 },
351 { 361 {
352 .config = (char *) "krava13", 362 .config = (char *) "krava13",
353 .val.num = 2, 363 .val.num = 2,
354 .type = PARSE_EVENTS__TERM_TYPE_NUM, 364 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
365 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
355 }, 366 },
356 { 367 {
357 .config = (char *) "krava21", 368 .config = (char *) "krava21",
358 .val.num = 119, 369 .val.num = 119,
359 .type = PARSE_EVENTS__TERM_TYPE_NUM, 370 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
371 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
360 }, 372 },
361 { 373 {
362 .config = (char *) "krava22", 374 .config = (char *) "krava22",
363 .val.num = 11, 375 .val.num = 11,
364 .type = PARSE_EVENTS__TERM_TYPE_NUM, 376 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
377 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
365 }, 378 },
366 { 379 {
367 .config = (char *) "krava23", 380 .config = (char *) "krava23",
368 .val.num = 2, 381 .val.num = 2,
369 .type = PARSE_EVENTS__TERM_TYPE_NUM, 382 .type_val = PARSE_EVENTS__TERM_TYPE_NUM,
383 .type_term = PARSE_EVENTS__TERM_TYPE_USER,
370 }, 384 },
371}; 385};
372#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term)) 386#define TERMS_CNT (sizeof(test_terms) / sizeof(struct parse_events__term))
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 8a8ee64e72d1..0dda25d82d06 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -44,6 +44,7 @@
44#include "trace-event.h" /* For __unused */ 44#include "trace-event.h" /* For __unused */
45#include "probe-event.h" 45#include "probe-event.h"
46#include "probe-finder.h" 46#include "probe-finder.h"
47#include "session.h"
47 48
48#define MAX_CMDLEN 256 49#define MAX_CMDLEN 256
49#define MAX_PROBE_ARGS 128 50#define MAX_PROBE_ARGS 128
@@ -70,6 +71,8 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
70} 71}
71 72
72static char *synthesize_perf_probe_point(struct perf_probe_point *pp); 73static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
74static int convert_name_to_addr(struct perf_probe_event *pev,
75 const char *exec);
73static struct machine machine; 76static struct machine machine;
74 77
75/* Initialize symbol maps and path of vmlinux/modules */ 78/* Initialize symbol maps and path of vmlinux/modules */
@@ -170,6 +173,34 @@ const char *kernel_get_module_path(const char *module)
170 return (dso) ? dso->long_name : NULL; 173 return (dso) ? dso->long_name : NULL;
171} 174}
172 175
176static int init_user_exec(void)
177{
178 int ret = 0;
179
180 symbol_conf.try_vmlinux_path = false;
181 symbol_conf.sort_by_name = true;
182 ret = symbol__init();
183
184 if (ret < 0)
185 pr_debug("Failed to init symbol map.\n");
186
187 return ret;
188}
189
190static int convert_to_perf_probe_point(struct probe_trace_point *tp,
191 struct perf_probe_point *pp)
192{
193 pp->function = strdup(tp->symbol);
194
195 if (pp->function == NULL)
196 return -ENOMEM;
197
198 pp->offset = tp->offset;
199 pp->retprobe = tp->retprobe;
200
201 return 0;
202}
203
173#ifdef DWARF_SUPPORT 204#ifdef DWARF_SUPPORT
174/* Open new debuginfo of given module */ 205/* Open new debuginfo of given module */
175static struct debuginfo *open_debuginfo(const char *module) 206static struct debuginfo *open_debuginfo(const char *module)
@@ -224,10 +255,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
224 if (ret <= 0) { 255 if (ret <= 0) {
225 pr_debug("Failed to find corresponding probes from " 256 pr_debug("Failed to find corresponding probes from "
226 "debuginfo. Use kprobe event information.\n"); 257 "debuginfo. Use kprobe event information.\n");
227 pp->function = strdup(tp->symbol); 258 return convert_to_perf_probe_point(tp, pp);
228 if (pp->function == NULL)
229 return -ENOMEM;
230 pp->offset = tp->offset;
231 } 259 }
232 pp->retprobe = tp->retprobe; 260 pp->retprobe = tp->retprobe;
233 261
@@ -275,9 +303,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
275 int max_tevs, const char *target) 303 int max_tevs, const char *target)
276{ 304{
277 bool need_dwarf = perf_probe_event_need_dwarf(pev); 305 bool need_dwarf = perf_probe_event_need_dwarf(pev);
278 struct debuginfo *dinfo = open_debuginfo(target); 306 struct debuginfo *dinfo;
279 int ntevs, ret = 0; 307 int ntevs, ret = 0;
280 308
309 if (pev->uprobes) {
310 if (need_dwarf) {
311 pr_warning("Debuginfo-analysis is not yet supported"
312 " with -x/--exec option.\n");
313 return -ENOSYS;
314 }
315 return convert_name_to_addr(pev, target);
316 }
317
318 dinfo = open_debuginfo(target);
319
281 if (!dinfo) { 320 if (!dinfo) {
282 if (need_dwarf) { 321 if (need_dwarf) {
283 pr_warning("Failed to open debuginfo file.\n"); 322 pr_warning("Failed to open debuginfo file.\n");
@@ -603,23 +642,22 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
603 pr_err("Failed to find symbol %s in kernel.\n", tp->symbol); 642 pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
604 return -ENOENT; 643 return -ENOENT;
605 } 644 }
606 pp->function = strdup(tp->symbol);
607 if (pp->function == NULL)
608 return -ENOMEM;
609 pp->offset = tp->offset;
610 pp->retprobe = tp->retprobe;
611 645
612 return 0; 646 return convert_to_perf_probe_point(tp, pp);
613} 647}
614 648
615static int try_to_find_probe_trace_events(struct perf_probe_event *pev, 649static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
616 struct probe_trace_event **tevs __unused, 650 struct probe_trace_event **tevs __unused,
617 int max_tevs __unused, const char *mod __unused) 651 int max_tevs __unused, const char *target)
618{ 652{
619 if (perf_probe_event_need_dwarf(pev)) { 653 if (perf_probe_event_need_dwarf(pev)) {
620 pr_warning("Debuginfo-analysis is not supported.\n"); 654 pr_warning("Debuginfo-analysis is not supported.\n");
621 return -ENOSYS; 655 return -ENOSYS;
622 } 656 }
657
658 if (pev->uprobes)
659 return convert_name_to_addr(pev, target);
660
623 return 0; 661 return 0;
624} 662}
625 663
@@ -1341,11 +1379,18 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev)
1341 if (buf == NULL) 1379 if (buf == NULL)
1342 return NULL; 1380 return NULL;
1343 1381
1344 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu", 1382 if (tev->uprobes)
1345 tp->retprobe ? 'r' : 'p', 1383 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s:%s",
1346 tev->group, tev->event, 1384 tp->retprobe ? 'r' : 'p',
1347 tp->module ?: "", tp->module ? ":" : "", 1385 tev->group, tev->event,
1348 tp->symbol, tp->offset); 1386 tp->module, tp->symbol);
1387 else
1388 len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s%s%s+%lu",
1389 tp->retprobe ? 'r' : 'p',
1390 tev->group, tev->event,
1391 tp->module ?: "", tp->module ? ":" : "",
1392 tp->symbol, tp->offset);
1393
1349 if (len <= 0) 1394 if (len <= 0)
1350 goto error; 1395 goto error;
1351 1396
@@ -1364,7 +1409,7 @@ error:
1364} 1409}
1365 1410
1366static int convert_to_perf_probe_event(struct probe_trace_event *tev, 1411static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1367 struct perf_probe_event *pev) 1412 struct perf_probe_event *pev, bool is_kprobe)
1368{ 1413{
1369 char buf[64] = ""; 1414 char buf[64] = "";
1370 int i, ret; 1415 int i, ret;
@@ -1376,7 +1421,11 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1376 return -ENOMEM; 1421 return -ENOMEM;
1377 1422
1378 /* Convert trace_point to probe_point */ 1423 /* Convert trace_point to probe_point */
1379 ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point); 1424 if (is_kprobe)
1425 ret = kprobe_convert_to_perf_probe(&tev->point, &pev->point);
1426 else
1427 ret = convert_to_perf_probe_point(&tev->point, &pev->point);
1428
1380 if (ret < 0) 1429 if (ret < 0)
1381 return ret; 1430 return ret;
1382 1431
@@ -1472,7 +1521,26 @@ static void clear_probe_trace_event(struct probe_trace_event *tev)
1472 memset(tev, 0, sizeof(*tev)); 1521 memset(tev, 0, sizeof(*tev));
1473} 1522}
1474 1523
1475static int open_kprobe_events(bool readwrite) 1524static void print_warn_msg(const char *file, bool is_kprobe)
1525{
1526
1527 if (errno == ENOENT) {
1528 const char *config;
1529
1530 if (!is_kprobe)
1531 config = "CONFIG_UPROBE_EVENTS";
1532 else
1533 config = "CONFIG_KPROBE_EVENTS";
1534
1535 pr_warning("%s file does not exist - please rebuild kernel"
1536 " with %s.\n", file, config);
1537 } else
1538 pr_warning("Failed to open %s file: %s\n", file,
1539 strerror(errno));
1540}
1541
1542static int open_probe_events(const char *trace_file, bool readwrite,
1543 bool is_kprobe)
1476{ 1544{
1477 char buf[PATH_MAX]; 1545 char buf[PATH_MAX];
1478 const char *__debugfs; 1546 const char *__debugfs;
@@ -1484,27 +1552,31 @@ static int open_kprobe_events(bool readwrite)
1484 return -ENOENT; 1552 return -ENOENT;
1485 } 1553 }
1486 1554
1487 ret = e_snprintf(buf, PATH_MAX, "%stracing/kprobe_events", __debugfs); 1555 ret = e_snprintf(buf, PATH_MAX, "%s/%s", __debugfs, trace_file);
1488 if (ret >= 0) { 1556 if (ret >= 0) {
1489 pr_debug("Opening %s write=%d\n", buf, readwrite); 1557 pr_debug("Opening %s write=%d\n", buf, readwrite);
1490 if (readwrite && !probe_event_dry_run) 1558 if (readwrite && !probe_event_dry_run)
1491 ret = open(buf, O_RDWR, O_APPEND); 1559 ret = open(buf, O_RDWR, O_APPEND);
1492 else 1560 else
1493 ret = open(buf, O_RDONLY, 0); 1561 ret = open(buf, O_RDONLY, 0);
1494 }
1495 1562
1496 if (ret < 0) { 1563 if (ret < 0)
1497 if (errno == ENOENT) 1564 print_warn_msg(buf, is_kprobe);
1498 pr_warning("kprobe_events file does not exist - please"
1499 " rebuild kernel with CONFIG_KPROBE_EVENT.\n");
1500 else
1501 pr_warning("Failed to open kprobe_events file: %s\n",
1502 strerror(errno));
1503 } 1565 }
1504 return ret; 1566 return ret;
1505} 1567}
1506 1568
1507/* Get raw string list of current kprobe_events */ 1569static int open_kprobe_events(bool readwrite)
1570{
1571 return open_probe_events("tracing/kprobe_events", readwrite, true);
1572}
1573
1574static int open_uprobe_events(bool readwrite)
1575{
1576 return open_probe_events("tracing/uprobe_events", readwrite, false);
1577}
1578
1579/* Get raw string list of current kprobe_events or uprobe_events */
1508static struct strlist *get_probe_trace_command_rawlist(int fd) 1580static struct strlist *get_probe_trace_command_rawlist(int fd)
1509{ 1581{
1510 int ret, idx; 1582 int ret, idx;
@@ -1569,36 +1641,26 @@ static int show_perf_probe_event(struct perf_probe_event *pev)
1569 return ret; 1641 return ret;
1570} 1642}
1571 1643
1572/* List up current perf-probe events */ 1644static int __show_perf_probe_events(int fd, bool is_kprobe)
1573int show_perf_probe_events(void)
1574{ 1645{
1575 int fd, ret; 1646 int ret = 0;
1576 struct probe_trace_event tev; 1647 struct probe_trace_event tev;
1577 struct perf_probe_event pev; 1648 struct perf_probe_event pev;
1578 struct strlist *rawlist; 1649 struct strlist *rawlist;
1579 struct str_node *ent; 1650 struct str_node *ent;
1580 1651
1581 setup_pager();
1582 ret = init_vmlinux();
1583 if (ret < 0)
1584 return ret;
1585
1586 memset(&tev, 0, sizeof(tev)); 1652 memset(&tev, 0, sizeof(tev));
1587 memset(&pev, 0, sizeof(pev)); 1653 memset(&pev, 0, sizeof(pev));
1588 1654
1589 fd = open_kprobe_events(false);
1590 if (fd < 0)
1591 return fd;
1592
1593 rawlist = get_probe_trace_command_rawlist(fd); 1655 rawlist = get_probe_trace_command_rawlist(fd);
1594 close(fd);
1595 if (!rawlist) 1656 if (!rawlist)
1596 return -ENOENT; 1657 return -ENOENT;
1597 1658
1598 strlist__for_each(ent, rawlist) { 1659 strlist__for_each(ent, rawlist) {
1599 ret = parse_probe_trace_command(ent->s, &tev); 1660 ret = parse_probe_trace_command(ent->s, &tev);
1600 if (ret >= 0) { 1661 if (ret >= 0) {
1601 ret = convert_to_perf_probe_event(&tev, &pev); 1662 ret = convert_to_perf_probe_event(&tev, &pev,
1663 is_kprobe);
1602 if (ret >= 0) 1664 if (ret >= 0)
1603 ret = show_perf_probe_event(&pev); 1665 ret = show_perf_probe_event(&pev);
1604 } 1666 }
@@ -1612,6 +1674,33 @@ int show_perf_probe_events(void)
1612 return ret; 1674 return ret;
1613} 1675}
1614 1676
1677/* List up current perf-probe events */
1678int show_perf_probe_events(void)
1679{
1680 int fd, ret;
1681
1682 setup_pager();
1683 fd = open_kprobe_events(false);
1684
1685 if (fd < 0)
1686 return fd;
1687
1688 ret = init_vmlinux();
1689 if (ret < 0)
1690 return ret;
1691
1692 ret = __show_perf_probe_events(fd, true);
1693 close(fd);
1694
1695 fd = open_uprobe_events(false);
1696 if (fd >= 0) {
1697 ret = __show_perf_probe_events(fd, false);
1698 close(fd);
1699 }
1700
1701 return ret;
1702}
1703
1615/* Get current perf-probe event names */ 1704/* Get current perf-probe event names */
1616static struct strlist *get_probe_trace_event_names(int fd, bool include_group) 1705static struct strlist *get_probe_trace_event_names(int fd, bool include_group)
1617{ 1706{
@@ -1717,7 +1806,11 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
1717 const char *event, *group; 1806 const char *event, *group;
1718 struct strlist *namelist; 1807 struct strlist *namelist;
1719 1808
1720 fd = open_kprobe_events(true); 1809 if (pev->uprobes)
1810 fd = open_uprobe_events(true);
1811 else
1812 fd = open_kprobe_events(true);
1813
1721 if (fd < 0) 1814 if (fd < 0)
1722 return fd; 1815 return fd;
1723 /* Get current event names */ 1816 /* Get current event names */
@@ -1829,6 +1922,8 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1829 tev->point.offset = pev->point.offset; 1922 tev->point.offset = pev->point.offset;
1830 tev->point.retprobe = pev->point.retprobe; 1923 tev->point.retprobe = pev->point.retprobe;
1831 tev->nargs = pev->nargs; 1924 tev->nargs = pev->nargs;
1925 tev->uprobes = pev->uprobes;
1926
1832 if (tev->nargs) { 1927 if (tev->nargs) {
1833 tev->args = zalloc(sizeof(struct probe_trace_arg) 1928 tev->args = zalloc(sizeof(struct probe_trace_arg)
1834 * tev->nargs); 1929 * tev->nargs);
@@ -1859,6 +1954,9 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
1859 } 1954 }
1860 } 1955 }
1861 1956
1957 if (pev->uprobes)
1958 return 1;
1959
1862 /* Currently just checking function name from symbol map */ 1960 /* Currently just checking function name from symbol map */
1863 sym = __find_kernel_function_by_name(tev->point.symbol, NULL); 1961 sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
1864 if (!sym) { 1962 if (!sym) {
@@ -1894,12 +1992,18 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
1894 int i, j, ret; 1992 int i, j, ret;
1895 struct __event_package *pkgs; 1993 struct __event_package *pkgs;
1896 1994
1995 ret = 0;
1897 pkgs = zalloc(sizeof(struct __event_package) * npevs); 1996 pkgs = zalloc(sizeof(struct __event_package) * npevs);
1997
1898 if (pkgs == NULL) 1998 if (pkgs == NULL)
1899 return -ENOMEM; 1999 return -ENOMEM;
1900 2000
1901 /* Init vmlinux path */ 2001 if (!pevs->uprobes)
1902 ret = init_vmlinux(); 2002 /* Init vmlinux path */
2003 ret = init_vmlinux();
2004 else
2005 ret = init_user_exec();
2006
1903 if (ret < 0) { 2007 if (ret < 0) {
1904 free(pkgs); 2008 free(pkgs);
1905 return ret; 2009 return ret;
@@ -1971,23 +2075,15 @@ error:
1971 return ret; 2075 return ret;
1972} 2076}
1973 2077
1974static int del_trace_probe_event(int fd, const char *group, 2078static int del_trace_probe_event(int fd, const char *buf,
1975 const char *event, struct strlist *namelist) 2079 struct strlist *namelist)
1976{ 2080{
1977 char buf[128];
1978 struct str_node *ent, *n; 2081 struct str_node *ent, *n;
1979 int found = 0, ret = 0; 2082 int ret = -1;
1980
1981 ret = e_snprintf(buf, 128, "%s:%s", group, event);
1982 if (ret < 0) {
1983 pr_err("Failed to copy event.\n");
1984 return ret;
1985 }
1986 2083
1987 if (strpbrk(buf, "*?")) { /* Glob-exp */ 2084 if (strpbrk(buf, "*?")) { /* Glob-exp */
1988 strlist__for_each_safe(ent, n, namelist) 2085 strlist__for_each_safe(ent, n, namelist)
1989 if (strglobmatch(ent->s, buf)) { 2086 if (strglobmatch(ent->s, buf)) {
1990 found++;
1991 ret = __del_trace_probe_event(fd, ent); 2087 ret = __del_trace_probe_event(fd, ent);
1992 if (ret < 0) 2088 if (ret < 0)
1993 break; 2089 break;
@@ -1996,40 +2092,43 @@ static int del_trace_probe_event(int fd, const char *group,
1996 } else { 2092 } else {
1997 ent = strlist__find(namelist, buf); 2093 ent = strlist__find(namelist, buf);
1998 if (ent) { 2094 if (ent) {
1999 found++;
2000 ret = __del_trace_probe_event(fd, ent); 2095 ret = __del_trace_probe_event(fd, ent);
2001 if (ret >= 0) 2096 if (ret >= 0)
2002 strlist__remove(namelist, ent); 2097 strlist__remove(namelist, ent);
2003 } 2098 }
2004 } 2099 }
2005 if (found == 0 && ret >= 0)
2006 pr_info("Info: Event \"%s\" does not exist.\n", buf);
2007 2100
2008 return ret; 2101 return ret;
2009} 2102}
2010 2103
2011int del_perf_probe_events(struct strlist *dellist) 2104int del_perf_probe_events(struct strlist *dellist)
2012{ 2105{
2013 int fd, ret = 0; 2106 int ret = -1, ufd = -1, kfd = -1;
2107 char buf[128];
2014 const char *group, *event; 2108 const char *group, *event;
2015 char *p, *str; 2109 char *p, *str;
2016 struct str_node *ent; 2110 struct str_node *ent;
2017 struct strlist *namelist; 2111 struct strlist *namelist = NULL, *unamelist = NULL;
2018
2019 fd = open_kprobe_events(true);
2020 if (fd < 0)
2021 return fd;
2022 2112
2023 /* Get current event names */ 2113 /* Get current event names */
2024 namelist = get_probe_trace_event_names(fd, true); 2114 kfd = open_kprobe_events(true);
2025 if (namelist == NULL) 2115 if (kfd < 0)
2026 return -EINVAL; 2116 return kfd;
2117
2118 namelist = get_probe_trace_event_names(kfd, true);
2119 ufd = open_uprobe_events(true);
2120
2121 if (ufd >= 0)
2122 unamelist = get_probe_trace_event_names(ufd, true);
2123
2124 if (namelist == NULL && unamelist == NULL)
2125 goto error;
2027 2126
2028 strlist__for_each(ent, dellist) { 2127 strlist__for_each(ent, dellist) {
2029 str = strdup(ent->s); 2128 str = strdup(ent->s);
2030 if (str == NULL) { 2129 if (str == NULL) {
2031 ret = -ENOMEM; 2130 ret = -ENOMEM;
2032 break; 2131 goto error;
2033 } 2132 }
2034 pr_debug("Parsing: %s\n", str); 2133 pr_debug("Parsing: %s\n", str);
2035 p = strchr(str, ':'); 2134 p = strchr(str, ':');
@@ -2041,17 +2140,42 @@ int del_perf_probe_events(struct strlist *dellist)
2041 group = "*"; 2140 group = "*";
2042 event = str; 2141 event = str;
2043 } 2142 }
2143
2144 ret = e_snprintf(buf, 128, "%s:%s", group, event);
2145 if (ret < 0) {
2146 pr_err("Failed to copy event.");
2147 free(str);
2148 goto error;
2149 }
2150
2044 pr_debug("Group: %s, Event: %s\n", group, event); 2151 pr_debug("Group: %s, Event: %s\n", group, event);
2045 ret = del_trace_probe_event(fd, group, event, namelist); 2152
2153 if (namelist)
2154 ret = del_trace_probe_event(kfd, buf, namelist);
2155
2156 if (unamelist && ret != 0)
2157 ret = del_trace_probe_event(ufd, buf, unamelist);
2158
2159 if (ret != 0)
2160 pr_info("Info: Event \"%s\" does not exist.\n", buf);
2161
2046 free(str); 2162 free(str);
2047 if (ret < 0)
2048 break;
2049 } 2163 }
2050 strlist__delete(namelist); 2164
2051 close(fd); 2165error:
2166 if (kfd >= 0) {
2167 strlist__delete(namelist);
2168 close(kfd);
2169 }
2170
2171 if (ufd >= 0) {
2172 strlist__delete(unamelist);
2173 close(ufd);
2174 }
2052 2175
2053 return ret; 2176 return ret;
2054} 2177}
2178
2055/* TODO: don't use a global variable for filter ... */ 2179/* TODO: don't use a global variable for filter ... */
2056static struct strfilter *available_func_filter; 2180static struct strfilter *available_func_filter;
2057 2181
@@ -2068,30 +2192,152 @@ static int filter_available_functions(struct map *map __unused,
2068 return 1; 2192 return 1;
2069} 2193}
2070 2194
2071int show_available_funcs(const char *target, struct strfilter *_filter) 2195static int __show_available_funcs(struct map *map)
2196{
2197 if (map__load(map, filter_available_functions)) {
2198 pr_err("Failed to load map.\n");
2199 return -EINVAL;
2200 }
2201 if (!dso__sorted_by_name(map->dso, map->type))
2202 dso__sort_by_name(map->dso, map->type);
2203
2204 dso__fprintf_symbols_by_name(map->dso, map->type, stdout);
2205 return 0;
2206}
2207
2208static int available_kernel_funcs(const char *module)
2072{ 2209{
2073 struct map *map; 2210 struct map *map;
2074 int ret; 2211 int ret;
2075 2212
2076 setup_pager();
2077
2078 ret = init_vmlinux(); 2213 ret = init_vmlinux();
2079 if (ret < 0) 2214 if (ret < 0)
2080 return ret; 2215 return ret;
2081 2216
2082 map = kernel_get_module_map(target); 2217 map = kernel_get_module_map(module);
2083 if (!map) { 2218 if (!map) {
2084 pr_err("Failed to find %s map.\n", (target) ? : "kernel"); 2219 pr_err("Failed to find %s map.\n", (module) ? : "kernel");
2085 return -EINVAL; 2220 return -EINVAL;
2086 } 2221 }
2222 return __show_available_funcs(map);
2223}
2224
2225static int available_user_funcs(const char *target)
2226{
2227 struct map *map;
2228 int ret;
2229
2230 ret = init_user_exec();
2231 if (ret < 0)
2232 return ret;
2233
2234 map = dso__new_map(target);
2235 ret = __show_available_funcs(map);
2236 dso__delete(map->dso);
2237 map__delete(map);
2238 return ret;
2239}
2240
2241int show_available_funcs(const char *target, struct strfilter *_filter,
2242 bool user)
2243{
2244 setup_pager();
2087 available_func_filter = _filter; 2245 available_func_filter = _filter;
2246
2247 if (!user)
2248 return available_kernel_funcs(target);
2249
2250 return available_user_funcs(target);
2251}
2252
2253/*
2254 * uprobe_events only accepts address:
2255 * Convert function and any offset to address
2256 */
2257static int convert_name_to_addr(struct perf_probe_event *pev, const char *exec)
2258{
2259 struct perf_probe_point *pp = &pev->point;
2260 struct symbol *sym;
2261 struct map *map = NULL;
2262 char *function = NULL, *name = NULL;
2263 int ret = -EINVAL;
2264 unsigned long long vaddr = 0;
2265
2266 if (!pp->function) {
2267 pr_warning("No function specified for uprobes");
2268 goto out;
2269 }
2270
2271 function = strdup(pp->function);
2272 if (!function) {
2273 pr_warning("Failed to allocate memory by strdup.\n");
2274 ret = -ENOMEM;
2275 goto out;
2276 }
2277
2278 name = realpath(exec, NULL);
2279 if (!name) {
2280 pr_warning("Cannot find realpath for %s.\n", exec);
2281 goto out;
2282 }
2283 map = dso__new_map(name);
2284 if (!map) {
2285 pr_warning("Cannot find appropriate DSO for %s.\n", exec);
2286 goto out;
2287 }
2288 available_func_filter = strfilter__new(function, NULL);
2088 if (map__load(map, filter_available_functions)) { 2289 if (map__load(map, filter_available_functions)) {
2089 pr_err("Failed to load map.\n"); 2290 pr_err("Failed to load map.\n");
2090 return -EINVAL; 2291 goto out;
2091 } 2292 }
2092 if (!dso__sorted_by_name(map->dso, map->type))
2093 dso__sort_by_name(map->dso, map->type);
2094 2293
2095 dso__fprintf_symbols_by_name(map->dso, map->type, stdout); 2294 sym = map__find_symbol_by_name(map, function, NULL);
2096 return 0; 2295 if (!sym) {
2296 pr_warning("Cannot find %s in DSO %s\n", function, exec);
2297 goto out;
2298 }
2299
2300 if (map->start > sym->start)
2301 vaddr = map->start;
2302 vaddr += sym->start + pp->offset + map->pgoff;
2303 pp->offset = 0;
2304
2305 if (!pev->event) {
2306 pev->event = function;
2307 function = NULL;
2308 }
2309 if (!pev->group) {
2310 char *ptr1, *ptr2;
2311
2312 pev->group = zalloc(sizeof(char *) * 64);
2313 ptr1 = strdup(basename(exec));
2314 if (ptr1) {
2315 ptr2 = strpbrk(ptr1, "-._");
2316 if (ptr2)
2317 *ptr2 = '\0';
2318 e_snprintf(pev->group, 64, "%s_%s", PERFPROBE_GROUP,
2319 ptr1);
2320 free(ptr1);
2321 }
2322 }
2323 free(pp->function);
2324 pp->function = zalloc(sizeof(char *) * MAX_PROBE_ARGS);
2325 if (!pp->function) {
2326 ret = -ENOMEM;
2327 pr_warning("Failed to allocate memory by zalloc.\n");
2328 goto out;
2329 }
2330 e_snprintf(pp->function, MAX_PROBE_ARGS, "0x%llx", vaddr);
2331 ret = 0;
2332
2333out:
2334 if (map) {
2335 dso__delete(map->dso);
2336 map__delete(map);
2337 }
2338 if (function)
2339 free(function);
2340 if (name)
2341 free(name);
2342 return ret;
2097} 2343}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index a7dee835f49c..f9f3de8b4220 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -7,7 +7,7 @@
7 7
8extern bool probe_event_dry_run; 8extern bool probe_event_dry_run;
9 9
10/* kprobe-tracer tracing point */ 10/* kprobe-tracer and uprobe-tracer tracing point */
11struct probe_trace_point { 11struct probe_trace_point {
12 char *symbol; /* Base symbol */ 12 char *symbol; /* Base symbol */
13 char *module; /* Module name */ 13 char *module; /* Module name */
@@ -21,7 +21,7 @@ struct probe_trace_arg_ref {
21 long offset; /* Offset value */ 21 long offset; /* Offset value */
22}; 22};
23 23
24/* kprobe-tracer tracing argument */ 24/* kprobe-tracer and uprobe-tracer tracing argument */
25struct probe_trace_arg { 25struct probe_trace_arg {
26 char *name; /* Argument name */ 26 char *name; /* Argument name */
27 char *value; /* Base value */ 27 char *value; /* Base value */
@@ -29,12 +29,13 @@ struct probe_trace_arg {
29 struct probe_trace_arg_ref *ref; /* Referencing offset */ 29 struct probe_trace_arg_ref *ref; /* Referencing offset */
30}; 30};
31 31
32/* kprobe-tracer tracing event (point + arg) */ 32/* kprobe-tracer and uprobe-tracer tracing event (point + arg) */
33struct probe_trace_event { 33struct probe_trace_event {
34 char *event; /* Event name */ 34 char *event; /* Event name */
35 char *group; /* Group name */ 35 char *group; /* Group name */
36 struct probe_trace_point point; /* Trace point */ 36 struct probe_trace_point point; /* Trace point */
37 int nargs; /* Number of args */ 37 int nargs; /* Number of args */
38 bool uprobes; /* uprobes only */
38 struct probe_trace_arg *args; /* Arguments */ 39 struct probe_trace_arg *args; /* Arguments */
39}; 40};
40 41
@@ -70,6 +71,7 @@ struct perf_probe_event {
70 char *group; /* Group name */ 71 char *group; /* Group name */
71 struct perf_probe_point point; /* Probe point */ 72 struct perf_probe_point point; /* Probe point */
72 int nargs; /* Number of arguments */ 73 int nargs; /* Number of arguments */
74 bool uprobes;
73 struct perf_probe_arg *args; /* Arguments */ 75 struct perf_probe_arg *args; /* Arguments */
74}; 76};
75 77
@@ -129,8 +131,8 @@ extern int show_line_range(struct line_range *lr, const char *module);
129extern int show_available_vars(struct perf_probe_event *pevs, int npevs, 131extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
130 int max_probe_points, const char *module, 132 int max_probe_points, const char *module,
131 struct strfilter *filter, bool externs); 133 struct strfilter *filter, bool externs);
132extern int show_available_funcs(const char *module, struct strfilter *filter); 134extern int show_available_funcs(const char *module, struct strfilter *filter,
133 135 bool user);
134 136
135/* Maximum index number of event-name postfix */ 137/* Maximum index number of event-name postfix */
136#define MAX_EVENT_INDEX 1024 138#define MAX_EVENT_INDEX 1024
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index e30749e38a9b..4c1b3d72a1d2 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -56,7 +56,7 @@ INTERP my_perl;
56#define FTRACE_MAX_EVENT \ 56#define FTRACE_MAX_EVENT \
57 ((1 << (sizeof(unsigned short) * 8)) - 1) 57 ((1 << (sizeof(unsigned short) * 8)) - 1)
58 58
59struct event *events[FTRACE_MAX_EVENT]; 59struct event_format *events[FTRACE_MAX_EVENT];
60 60
61extern struct scripting_context *scripting_context; 61extern struct scripting_context *scripting_context;
62 62
@@ -181,7 +181,7 @@ static void define_flag_field(const char *ev_name,
181 LEAVE; 181 LEAVE;
182} 182}
183 183
184static void define_event_symbols(struct event *event, 184static void define_event_symbols(struct event_format *event,
185 const char *ev_name, 185 const char *ev_name,
186 struct print_arg *args) 186 struct print_arg *args)
187{ 187{
@@ -209,6 +209,8 @@ static void define_event_symbols(struct event *event,
209 define_symbolic_values(args->symbol.symbols, ev_name, 209 define_symbolic_values(args->symbol.symbols, ev_name,
210 cur_field_name); 210 cur_field_name);
211 break; 211 break;
212 case PRINT_BSTRING:
213 case PRINT_DYNAMIC_ARRAY:
212 case PRINT_STRING: 214 case PRINT_STRING:
213 break; 215 break;
214 case PRINT_TYPE: 216 case PRINT_TYPE:
@@ -220,7 +222,9 @@ static void define_event_symbols(struct event *event,
220 define_event_symbols(event, ev_name, args->op.left); 222 define_event_symbols(event, ev_name, args->op.left);
221 define_event_symbols(event, ev_name, args->op.right); 223 define_event_symbols(event, ev_name, args->op.right);
222 break; 224 break;
225 case PRINT_FUNC:
223 default: 226 default:
227 pr_err("Unsupported print arg type\n");
224 /* we should warn... */ 228 /* we should warn... */
225 return; 229 return;
226 } 230 }
@@ -229,10 +233,10 @@ static void define_event_symbols(struct event *event,
229 define_event_symbols(event, ev_name, args->next); 233 define_event_symbols(event, ev_name, args->next);
230} 234}
231 235
232static inline struct event *find_cache_event(int type) 236static inline struct event_format *find_cache_event(int type)
233{ 237{
234 static char ev_name[256]; 238 static char ev_name[256];
235 struct event *event; 239 struct event_format *event;
236 240
237 if (events[type]) 241 if (events[type])
238 return events[type]; 242 return events[type];
@@ -258,7 +262,7 @@ static void perl_process_tracepoint(union perf_event *pevent __unused,
258 static char handler[256]; 262 static char handler[256];
259 unsigned long long val; 263 unsigned long long val;
260 unsigned long s, ns; 264 unsigned long s, ns;
261 struct event *event; 265 struct event_format *event;
262 int type; 266 int type;
263 int pid; 267 int pid;
264 int cpu = sample->cpu; 268 int cpu = sample->cpu;
@@ -446,7 +450,7 @@ static int perl_stop_script(void)
446 450
447static int perl_generate_script(const char *outfile) 451static int perl_generate_script(const char *outfile)
448{ 452{
449 struct event *event = NULL; 453 struct event_format *event = NULL;
450 struct format_field *f; 454 struct format_field *f;
451 char fname[PATH_MAX]; 455 char fname[PATH_MAX];
452 int not_first, count; 456 int not_first, count;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index c2623c6f9b51..acb9795286c4 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -37,7 +37,7 @@ PyMODINIT_FUNC initperf_trace_context(void);
37#define FTRACE_MAX_EVENT \ 37#define FTRACE_MAX_EVENT \
38 ((1 << (sizeof(unsigned short) * 8)) - 1) 38 ((1 << (sizeof(unsigned short) * 8)) - 1)
39 39
40struct event *events[FTRACE_MAX_EVENT]; 40struct event_format *events[FTRACE_MAX_EVENT];
41 41
42#define MAX_FIELDS 64 42#define MAX_FIELDS 64
43#define N_COMMON_FIELDS 7 43#define N_COMMON_FIELDS 7
@@ -136,7 +136,7 @@ static void define_field(enum print_arg_type field_type,
136 Py_DECREF(t); 136 Py_DECREF(t);
137} 137}
138 138
139static void define_event_symbols(struct event *event, 139static void define_event_symbols(struct event_format *event,
140 const char *ev_name, 140 const char *ev_name,
141 struct print_arg *args) 141 struct print_arg *args)
142{ 142{
@@ -178,6 +178,10 @@ static void define_event_symbols(struct event *event,
178 define_event_symbols(event, ev_name, args->op.right); 178 define_event_symbols(event, ev_name, args->op.right);
179 break; 179 break;
180 default: 180 default:
181 /* gcc warns for these? */
182 case PRINT_BSTRING:
183 case PRINT_DYNAMIC_ARRAY:
184 case PRINT_FUNC:
181 /* we should warn... */ 185 /* we should warn... */
182 return; 186 return;
183 } 187 }
@@ -186,10 +190,10 @@ static void define_event_symbols(struct event *event,
186 define_event_symbols(event, ev_name, args->next); 190 define_event_symbols(event, ev_name, args->next);
187} 191}
188 192
189static inline struct event *find_cache_event(int type) 193static inline struct event_format *find_cache_event(int type)
190{ 194{
191 static char ev_name[256]; 195 static char ev_name[256];
192 struct event *event; 196 struct event_format *event;
193 197
194 if (events[type]) 198 if (events[type])
195 return events[type]; 199 return events[type];
@@ -216,7 +220,7 @@ static void python_process_event(union perf_event *pevent __unused,
216 struct format_field *field; 220 struct format_field *field;
217 unsigned long long val; 221 unsigned long long val;
218 unsigned long s, ns; 222 unsigned long s, ns;
219 struct event *event; 223 struct event_format *event;
220 unsigned n = 0; 224 unsigned n = 0;
221 int type; 225 int type;
222 int pid; 226 int pid;
@@ -436,7 +440,7 @@ out:
436 440
437static int python_generate_script(const char *outfile) 441static int python_generate_script(const char *outfile)
438{ 442{
439 struct event *event = NULL; 443 struct event_format *event = NULL;
440 struct format_field *f; 444 struct format_field *f;
441 char fname[PATH_MAX]; 445 char fname[PATH_MAX];
442 int not_first, count; 446 int not_first, count;
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 1efd3bee6336..c3e399bcf18d 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -288,7 +288,8 @@ struct branch_info *machine__resolve_bstack(struct machine *self,
288 return bi; 288 return bi;
289} 289}
290 290
291int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel, 291int machine__resolve_callchain(struct machine *self,
292 struct perf_evsel *evsel __used,
292 struct thread *thread, 293 struct thread *thread,
293 struct ip_callchain *chain, 294 struct ip_callchain *chain,
294 struct symbol **parent) 295 struct symbol **parent)
@@ -297,7 +298,12 @@ int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel,
297 unsigned int i; 298 unsigned int i;
298 int err; 299 int err;
299 300
300 callchain_cursor_reset(&evsel->hists.callchain_cursor); 301 callchain_cursor_reset(&callchain_cursor);
302
303 if (chain->nr > PERF_MAX_STACK_DEPTH) {
304 pr_warning("corrupted callchain. skipping...\n");
305 return 0;
306 }
301 307
302 for (i = 0; i < chain->nr; i++) { 308 for (i = 0; i < chain->nr; i++) {
303 u64 ip; 309 u64 ip;
@@ -317,7 +323,14 @@ int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel,
317 case PERF_CONTEXT_USER: 323 case PERF_CONTEXT_USER:
318 cpumode = PERF_RECORD_MISC_USER; break; 324 cpumode = PERF_RECORD_MISC_USER; break;
319 default: 325 default:
320 break; 326 pr_debug("invalid callchain context: "
327 "%"PRId64"\n", (s64) ip);
328 /*
329 * It seems the callchain is corrupted.
330 * Discard all.
331 */
332 callchain_cursor_reset(&callchain_cursor);
333 return 0;
321 } 334 }
322 continue; 335 continue;
323 } 336 }
@@ -333,7 +346,7 @@ int machine__resolve_callchain(struct machine *self, struct perf_evsel *evsel,
333 break; 346 break;
334 } 347 }
335 348
336 err = callchain_cursor_append(&evsel->hists.callchain_cursor, 349 err = callchain_cursor_append(&callchain_cursor,
337 ip, al.map, al.sym); 350 ip, al.map, al.sym);
338 if (err) 351 if (err)
339 return err; 352 return err;
@@ -429,6 +442,16 @@ static void perf_tool__fill_defaults(struct perf_tool *tool)
429 tool->finished_round = process_finished_round_stub; 442 tool->finished_round = process_finished_round_stub;
430 } 443 }
431} 444}
445
446void mem_bswap_32(void *src, int byte_size)
447{
448 u32 *m = src;
449 while (byte_size > 0) {
450 *m = bswap_32(*m);
451 byte_size -= sizeof(u32);
452 ++m;
453 }
454}
432 455
433void mem_bswap_64(void *src, int byte_size) 456void mem_bswap_64(void *src, int byte_size)
434{ 457{
@@ -441,37 +464,65 @@ void mem_bswap_64(void *src, int byte_size)
441 } 464 }
442} 465}
443 466
444static void perf_event__all64_swap(union perf_event *event) 467static void swap_sample_id_all(union perf_event *event, void *data)
468{
469 void *end = (void *) event + event->header.size;
470 int size = end - data;
471
472 BUG_ON(size % sizeof(u64));
473 mem_bswap_64(data, size);
474}
475
476static void perf_event__all64_swap(union perf_event *event,
477 bool sample_id_all __used)
445{ 478{
446 struct perf_event_header *hdr = &event->header; 479 struct perf_event_header *hdr = &event->header;
447 mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr)); 480 mem_bswap_64(hdr + 1, event->header.size - sizeof(*hdr));
448} 481}
449 482
450static void perf_event__comm_swap(union perf_event *event) 483static void perf_event__comm_swap(union perf_event *event, bool sample_id_all)
451{ 484{
452 event->comm.pid = bswap_32(event->comm.pid); 485 event->comm.pid = bswap_32(event->comm.pid);
453 event->comm.tid = bswap_32(event->comm.tid); 486 event->comm.tid = bswap_32(event->comm.tid);
487
488 if (sample_id_all) {
489 void *data = &event->comm.comm;
490
491 data += ALIGN(strlen(data) + 1, sizeof(u64));
492 swap_sample_id_all(event, data);
493 }
454} 494}
455 495
456static void perf_event__mmap_swap(union perf_event *event) 496static void perf_event__mmap_swap(union perf_event *event,
497 bool sample_id_all)
457{ 498{
458 event->mmap.pid = bswap_32(event->mmap.pid); 499 event->mmap.pid = bswap_32(event->mmap.pid);
459 event->mmap.tid = bswap_32(event->mmap.tid); 500 event->mmap.tid = bswap_32(event->mmap.tid);
460 event->mmap.start = bswap_64(event->mmap.start); 501 event->mmap.start = bswap_64(event->mmap.start);
461 event->mmap.len = bswap_64(event->mmap.len); 502 event->mmap.len = bswap_64(event->mmap.len);
462 event->mmap.pgoff = bswap_64(event->mmap.pgoff); 503 event->mmap.pgoff = bswap_64(event->mmap.pgoff);
504
505 if (sample_id_all) {
506 void *data = &event->mmap.filename;
507
508 data += ALIGN(strlen(data) + 1, sizeof(u64));
509 swap_sample_id_all(event, data);
510 }
463} 511}
464 512
465static void perf_event__task_swap(union perf_event *event) 513static void perf_event__task_swap(union perf_event *event, bool sample_id_all)
466{ 514{
467 event->fork.pid = bswap_32(event->fork.pid); 515 event->fork.pid = bswap_32(event->fork.pid);
468 event->fork.tid = bswap_32(event->fork.tid); 516 event->fork.tid = bswap_32(event->fork.tid);
469 event->fork.ppid = bswap_32(event->fork.ppid); 517 event->fork.ppid = bswap_32(event->fork.ppid);
470 event->fork.ptid = bswap_32(event->fork.ptid); 518 event->fork.ptid = bswap_32(event->fork.ptid);
471 event->fork.time = bswap_64(event->fork.time); 519 event->fork.time = bswap_64(event->fork.time);
520
521 if (sample_id_all)
522 swap_sample_id_all(event, &event->fork + 1);
472} 523}
473 524
474static void perf_event__read_swap(union perf_event *event) 525static void perf_event__read_swap(union perf_event *event, bool sample_id_all)
475{ 526{
476 event->read.pid = bswap_32(event->read.pid); 527 event->read.pid = bswap_32(event->read.pid);
477 event->read.tid = bswap_32(event->read.tid); 528 event->read.tid = bswap_32(event->read.tid);
@@ -479,6 +530,41 @@ static void perf_event__read_swap(union perf_event *event)
479 event->read.time_enabled = bswap_64(event->read.time_enabled); 530 event->read.time_enabled = bswap_64(event->read.time_enabled);
480 event->read.time_running = bswap_64(event->read.time_running); 531 event->read.time_running = bswap_64(event->read.time_running);
481 event->read.id = bswap_64(event->read.id); 532 event->read.id = bswap_64(event->read.id);
533
534 if (sample_id_all)
535 swap_sample_id_all(event, &event->read + 1);
536}
537
538static u8 revbyte(u8 b)
539{
540 int rev = (b >> 4) | ((b & 0xf) << 4);
541 rev = ((rev & 0xcc) >> 2) | ((rev & 0x33) << 2);
542 rev = ((rev & 0xaa) >> 1) | ((rev & 0x55) << 1);
543 return (u8) rev;
544}
545
546/*
547 * XXX this is hack in attempt to carry flags bitfield
548 * throught endian village. ABI says:
549 *
550 * Bit-fields are allocated from right to left (least to most significant)
551 * on little-endian implementations and from left to right (most to least
552 * significant) on big-endian implementations.
553 *
554 * The above seems to be byte specific, so we need to reverse each
555 * byte of the bitfield. 'Internet' also says this might be implementation
556 * specific and we probably need proper fix and carry perf_event_attr
557 * bitfield flags in separate data file FEAT_ section. Thought this seems
558 * to work for now.
559 */
560static void swap_bitfield(u8 *p, unsigned len)
561{
562 unsigned i;
563
564 for (i = 0; i < len; i++) {
565 *p = revbyte(*p);
566 p++;
567 }
482} 568}
483 569
484/* exported for swapping attributes in file header */ 570/* exported for swapping attributes in file header */
@@ -494,9 +580,12 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
494 attr->bp_type = bswap_32(attr->bp_type); 580 attr->bp_type = bswap_32(attr->bp_type);
495 attr->bp_addr = bswap_64(attr->bp_addr); 581 attr->bp_addr = bswap_64(attr->bp_addr);
496 attr->bp_len = bswap_64(attr->bp_len); 582 attr->bp_len = bswap_64(attr->bp_len);
583
584 swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));
497} 585}
498 586
499static void perf_event__hdr_attr_swap(union perf_event *event) 587static void perf_event__hdr_attr_swap(union perf_event *event,
588 bool sample_id_all __used)
500{ 589{
501 size_t size; 590 size_t size;
502 591
@@ -507,18 +596,21 @@ static void perf_event__hdr_attr_swap(union perf_event *event)
507 mem_bswap_64(event->attr.id, size); 596 mem_bswap_64(event->attr.id, size);
508} 597}
509 598
510static void perf_event__event_type_swap(union perf_event *event) 599static void perf_event__event_type_swap(union perf_event *event,
600 bool sample_id_all __used)
511{ 601{
512 event->event_type.event_type.event_id = 602 event->event_type.event_type.event_id =
513 bswap_64(event->event_type.event_type.event_id); 603 bswap_64(event->event_type.event_type.event_id);
514} 604}
515 605
516static void perf_event__tracing_data_swap(union perf_event *event) 606static void perf_event__tracing_data_swap(union perf_event *event,
607 bool sample_id_all __used)
517{ 608{
518 event->tracing_data.size = bswap_32(event->tracing_data.size); 609 event->tracing_data.size = bswap_32(event->tracing_data.size);
519} 610}
520 611
521typedef void (*perf_event__swap_op)(union perf_event *event); 612typedef void (*perf_event__swap_op)(union perf_event *event,
613 bool sample_id_all);
522 614
523static perf_event__swap_op perf_event__swap_ops[] = { 615static perf_event__swap_op perf_event__swap_ops[] = {
524 [PERF_RECORD_MMAP] = perf_event__mmap_swap, 616 [PERF_RECORD_MMAP] = perf_event__mmap_swap,
@@ -952,6 +1044,15 @@ static int perf_session__process_user_event(struct perf_session *session, union
952 } 1044 }
953} 1045}
954 1046
1047static void event_swap(union perf_event *event, bool sample_id_all)
1048{
1049 perf_event__swap_op swap;
1050
1051 swap = perf_event__swap_ops[event->header.type];
1052 if (swap)
1053 swap(event, sample_id_all);
1054}
1055
955static int perf_session__process_event(struct perf_session *session, 1056static int perf_session__process_event(struct perf_session *session,
956 union perf_event *event, 1057 union perf_event *event,
957 struct perf_tool *tool, 1058 struct perf_tool *tool,
@@ -960,9 +1061,8 @@ static int perf_session__process_event(struct perf_session *session,
960 struct perf_sample sample; 1061 struct perf_sample sample;
961 int ret; 1062 int ret;
962 1063
963 if (session->header.needs_swap && 1064 if (session->header.needs_swap)
964 perf_event__swap_ops[event->header.type]) 1065 event_swap(event, session->sample_id_all);
965 perf_event__swap_ops[event->header.type](event);
966 1066
967 if (event->header.type >= PERF_RECORD_HEADER_MAX) 1067 if (event->header.type >= PERF_RECORD_HEADER_MAX)
968 return -EINVAL; 1068 return -EINVAL;
@@ -1064,8 +1164,9 @@ volatile int session_done;
1064static int __perf_session__process_pipe_events(struct perf_session *self, 1164static int __perf_session__process_pipe_events(struct perf_session *self,
1065 struct perf_tool *tool) 1165 struct perf_tool *tool)
1066{ 1166{
1067 union perf_event event; 1167 union perf_event *event;
1068 uint32_t size; 1168 uint32_t size, cur_size = 0;
1169 void *buf = NULL;
1069 int skip = 0; 1170 int skip = 0;
1070 u64 head; 1171 u64 head;
1071 int err; 1172 int err;
@@ -1074,8 +1175,14 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
1074 perf_tool__fill_defaults(tool); 1175 perf_tool__fill_defaults(tool);
1075 1176
1076 head = 0; 1177 head = 0;
1178 cur_size = sizeof(union perf_event);
1179
1180 buf = malloc(cur_size);
1181 if (!buf)
1182 return -errno;
1077more: 1183more:
1078 err = readn(self->fd, &event, sizeof(struct perf_event_header)); 1184 event = buf;
1185 err = readn(self->fd, event, sizeof(struct perf_event_header));
1079 if (err <= 0) { 1186 if (err <= 0) {
1080 if (err == 0) 1187 if (err == 0)
1081 goto done; 1188 goto done;
@@ -1085,13 +1192,23 @@ more:
1085 } 1192 }
1086 1193
1087 if (self->header.needs_swap) 1194 if (self->header.needs_swap)
1088 perf_event_header__bswap(&event.header); 1195 perf_event_header__bswap(&event->header);
1089 1196
1090 size = event.header.size; 1197 size = event->header.size;
1091 if (size == 0) 1198 if (size == 0)
1092 size = 8; 1199 size = 8;
1093 1200
1094 p = &event; 1201 if (size > cur_size) {
1202 void *new = realloc(buf, size);
1203 if (!new) {
1204 pr_err("failed to allocate memory to read event\n");
1205 goto out_err;
1206 }
1207 buf = new;
1208 cur_size = size;
1209 event = buf;
1210 }
1211 p = event;
1095 p += sizeof(struct perf_event_header); 1212 p += sizeof(struct perf_event_header);
1096 1213
1097 if (size - sizeof(struct perf_event_header)) { 1214 if (size - sizeof(struct perf_event_header)) {
@@ -1107,17 +1224,11 @@ more:
1107 } 1224 }
1108 } 1225 }
1109 1226
1110 if ((skip = perf_session__process_event(self, &event, tool, head)) < 0) { 1227 if ((skip = perf_session__process_event(self, event, tool, head)) < 0) {
1111 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", 1228 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
1112 head, event.header.size, event.header.type); 1229 head, event->header.size, event->header.type);
1113 /* 1230 err = -EINVAL;
1114 * assume we lost track of the stream, check alignment, and 1231 goto out_err;
1115 * increment a single u64 in the hope to catch on again 'soon'.
1116 */
1117 if (unlikely(head & 7))
1118 head &= ~7ULL;
1119
1120 size = 8;
1121 } 1232 }
1122 1233
1123 head += size; 1234 head += size;
@@ -1130,6 +1241,7 @@ more:
1130done: 1241done:
1131 err = 0; 1242 err = 0;
1132out_err: 1243out_err:
1244 free(buf);
1133 perf_session__warn_about_errors(self, tool); 1245 perf_session__warn_about_errors(self, tool);
1134 perf_session_free_sample_buffers(self); 1246 perf_session_free_sample_buffers(self);
1135 return err; 1247 return err;
@@ -1226,17 +1338,11 @@ more:
1226 1338
1227 if (size == 0 || 1339 if (size == 0 ||
1228 perf_session__process_event(session, event, tool, file_pos) < 0) { 1340 perf_session__process_event(session, event, tool, file_pos) < 0) {
1229 dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", 1341 pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
1230 file_offset + head, event->header.size, 1342 file_offset + head, event->header.size,
1231 event->header.type); 1343 event->header.type);
1232 /* 1344 err = -EINVAL;
1233 * assume we lost track of the stream, check alignment, and 1345 goto out_err;
1234 * increment a single u64 in the hope to catch on again 'soon'.
1235 */
1236 if (unlikely(head & 7))
1237 head &= ~7ULL;
1238
1239 size = 8;
1240 } 1346 }
1241 1347
1242 head += size; 1348 head += size;
@@ -1388,7 +1494,6 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1388 int print_sym, int print_dso, int print_symoffset) 1494 int print_sym, int print_dso, int print_symoffset)
1389{ 1495{
1390 struct addr_location al; 1496 struct addr_location al;
1391 struct callchain_cursor *cursor = &evsel->hists.callchain_cursor;
1392 struct callchain_cursor_node *node; 1497 struct callchain_cursor_node *node;
1393 1498
1394 if (perf_event__preprocess_sample(event, machine, &al, sample, 1499 if (perf_event__preprocess_sample(event, machine, &al, sample,
@@ -1406,10 +1511,10 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1406 error("Failed to resolve callchain. Skipping\n"); 1511 error("Failed to resolve callchain. Skipping\n");
1407 return; 1512 return;
1408 } 1513 }
1409 callchain_cursor_commit(cursor); 1514 callchain_cursor_commit(&callchain_cursor);
1410 1515
1411 while (1) { 1516 while (1) {
1412 node = callchain_cursor_current(cursor); 1517 node = callchain_cursor_current(&callchain_cursor);
1413 if (!node) 1518 if (!node)
1414 break; 1519 break;
1415 1520
@@ -1420,12 +1525,12 @@ void perf_event__print_ip(union perf_event *event, struct perf_sample *sample,
1420 } 1525 }
1421 if (print_dso) { 1526 if (print_dso) {
1422 printf(" ("); 1527 printf(" (");
1423 map__fprintf_dsoname(al.map, stdout); 1528 map__fprintf_dsoname(node->map, stdout);
1424 printf(")"); 1529 printf(")");
1425 } 1530 }
1426 printf("\n"); 1531 printf("\n");
1427 1532
1428 callchain_cursor_advance(cursor); 1533 callchain_cursor_advance(&callchain_cursor);
1429 } 1534 }
1430 1535
1431 } else { 1536 } else {
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 7a5434c00565..0c702e3f0a36 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -80,6 +80,7 @@ struct branch_info *machine__resolve_bstack(struct machine *self,
80bool perf_session__has_traces(struct perf_session *self, const char *msg); 80bool perf_session__has_traces(struct perf_session *self, const char *msg);
81 81
82void mem_bswap_64(void *src, int byte_size); 82void mem_bswap_64(void *src, int byte_size);
83void mem_bswap_32(void *src, int byte_size);
83void perf_event__attr_swap(struct perf_event_attr *attr); 84void perf_event__attr_swap(struct perf_event_attr *attr);
84 85
85int perf_session__create_kernel_maps(struct perf_session *self); 86int perf_session__create_kernel_maps(struct perf_session *self);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index c0a028c3ebaf..3e2e5ea0f03f 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -323,6 +323,7 @@ struct dso *dso__new(const char *name)
323 dso->sorted_by_name = 0; 323 dso->sorted_by_name = 0;
324 dso->has_build_id = 0; 324 dso->has_build_id = 0;
325 dso->kernel = DSO_TYPE_USER; 325 dso->kernel = DSO_TYPE_USER;
326 dso->needs_swap = DSO_SWAP__UNSET;
326 INIT_LIST_HEAD(&dso->node); 327 INIT_LIST_HEAD(&dso->node);
327 } 328 }
328 329
@@ -977,8 +978,9 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
977 * And always look at the original dso, not at debuginfo packages, that 978 * And always look at the original dso, not at debuginfo packages, that
978 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). 979 * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
979 */ 980 */
980static int dso__synthesize_plt_symbols(struct dso *dso, struct map *map, 981static int
981 symbol_filter_t filter) 982dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map,
983 symbol_filter_t filter)
982{ 984{
983 uint32_t nr_rel_entries, idx; 985 uint32_t nr_rel_entries, idx;
984 GElf_Sym sym; 986 GElf_Sym sym;
@@ -993,10 +995,7 @@ static int dso__synthesize_plt_symbols(struct dso *dso, struct map *map,
993 char sympltname[1024]; 995 char sympltname[1024];
994 Elf *elf; 996 Elf *elf;
995 int nr = 0, symidx, fd, err = 0; 997 int nr = 0, symidx, fd, err = 0;
996 char name[PATH_MAX];
997 998
998 snprintf(name, sizeof(name), "%s%s",
999 symbol_conf.symfs, dso->long_name);
1000 fd = open(name, O_RDONLY); 999 fd = open(name, O_RDONLY);
1001 if (fd < 0) 1000 if (fd < 0)
1002 goto out; 1001 goto out;
@@ -1158,6 +1157,33 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
1158 return -1; 1157 return -1;
1159} 1158}
1160 1159
1160static int dso__swap_init(struct dso *dso, unsigned char eidata)
1161{
1162 static unsigned int const endian = 1;
1163
1164 dso->needs_swap = DSO_SWAP__NO;
1165
1166 switch (eidata) {
1167 case ELFDATA2LSB:
1168 /* We are big endian, DSO is little endian. */
1169 if (*(unsigned char const *)&endian != 1)
1170 dso->needs_swap = DSO_SWAP__YES;
1171 break;
1172
1173 case ELFDATA2MSB:
1174 /* We are little endian, DSO is big endian. */
1175 if (*(unsigned char const *)&endian != 0)
1176 dso->needs_swap = DSO_SWAP__YES;
1177 break;
1178
1179 default:
1180 pr_err("unrecognized DSO data encoding %d\n", eidata);
1181 return -EINVAL;
1182 }
1183
1184 return 0;
1185}
1186
1161static int dso__load_sym(struct dso *dso, struct map *map, const char *name, 1187static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
1162 int fd, symbol_filter_t filter, int kmodule, 1188 int fd, symbol_filter_t filter, int kmodule,
1163 int want_symtab) 1189 int want_symtab)
@@ -1189,6 +1215,9 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
1189 goto out_elf_end; 1215 goto out_elf_end;
1190 } 1216 }
1191 1217
1218 if (dso__swap_init(dso, ehdr.e_ident[EI_DATA]))
1219 goto out_elf_end;
1220
1192 /* Always reject images with a mismatched build-id: */ 1221 /* Always reject images with a mismatched build-id: */
1193 if (dso->has_build_id) { 1222 if (dso->has_build_id) {
1194 u8 build_id[BUILD_ID_SIZE]; 1223 u8 build_id[BUILD_ID_SIZE];
@@ -1274,7 +1303,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name,
1274 if (opdsec && sym.st_shndx == opdidx) { 1303 if (opdsec && sym.st_shndx == opdidx) {
1275 u32 offset = sym.st_value - opdshdr.sh_addr; 1304 u32 offset = sym.st_value - opdshdr.sh_addr;
1276 u64 *opd = opddata->d_buf + offset; 1305 u64 *opd = opddata->d_buf + offset;
1277 sym.st_value = *opd; 1306 sym.st_value = DSO__SWAP(dso, u64, *opd);
1278 sym.st_shndx = elf_addr_to_index(elf, sym.st_value); 1307 sym.st_shndx = elf_addr_to_index(elf, sym.st_value);
1279 } 1308 }
1280 1309
@@ -1703,8 +1732,9 @@ restart:
1703 continue; 1732 continue;
1704 1733
1705 if (ret > 0) { 1734 if (ret > 0) {
1706 int nr_plt = dso__synthesize_plt_symbols(dso, map, 1735 int nr_plt;
1707 filter); 1736
1737 nr_plt = dso__synthesize_plt_symbols(dso, name, map, filter);
1708 if (nr_plt > 0) 1738 if (nr_plt > 0)
1709 ret += nr_plt; 1739 ret += nr_plt;
1710 break; 1740 break;
@@ -2784,3 +2814,14 @@ int machine__load_vmlinux_path(struct machine *machine, enum map_type type,
2784 2814
2785 return ret; 2815 return ret;
2786} 2816}
2817
2818struct map *dso__new_map(const char *name)
2819{
2820 struct map *map = NULL;
2821 struct dso *dso = dso__new(name);
2822
2823 if (dso)
2824 map = map__new2(0, dso, MAP__FUNCTION);
2825
2826 return map;
2827}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index ac49ef208a5f..af0752b1aca1 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -9,6 +9,7 @@
9#include <linux/list.h> 9#include <linux/list.h>
10#include <linux/rbtree.h> 10#include <linux/rbtree.h>
11#include <stdio.h> 11#include <stdio.h>
12#include <byteswap.h>
12 13
13#ifdef HAVE_CPLUS_DEMANGLE 14#ifdef HAVE_CPLUS_DEMANGLE
14extern char *cplus_demangle(const char *, int); 15extern char *cplus_demangle(const char *, int);
@@ -65,6 +66,11 @@ struct symbol {
65 66
66void symbol__delete(struct symbol *sym); 67void symbol__delete(struct symbol *sym);
67 68
69static inline size_t symbol__size(const struct symbol *sym)
70{
71 return sym->end - sym->start + 1;
72}
73
68struct strlist; 74struct strlist;
69 75
70struct symbol_conf { 76struct symbol_conf {
@@ -155,11 +161,18 @@ enum dso_kernel_type {
155 DSO_TYPE_GUEST_KERNEL 161 DSO_TYPE_GUEST_KERNEL
156}; 162};
157 163
164enum dso_swap_type {
165 DSO_SWAP__UNSET,
166 DSO_SWAP__NO,
167 DSO_SWAP__YES,
168};
169
158struct dso { 170struct dso {
159 struct list_head node; 171 struct list_head node;
160 struct rb_root symbols[MAP__NR_TYPES]; 172 struct rb_root symbols[MAP__NR_TYPES];
161 struct rb_root symbol_names[MAP__NR_TYPES]; 173 struct rb_root symbol_names[MAP__NR_TYPES];
162 enum dso_kernel_type kernel; 174 enum dso_kernel_type kernel;
175 enum dso_swap_type needs_swap;
163 u8 adjust_symbols:1; 176 u8 adjust_symbols:1;
164 u8 has_build_id:1; 177 u8 has_build_id:1;
165 u8 hit:1; 178 u8 hit:1;
@@ -177,6 +190,28 @@ struct dso {
177 char name[0]; 190 char name[0];
178}; 191};
179 192
193#define DSO__SWAP(dso, type, val) \
194({ \
195 type ____r = val; \
196 BUG_ON(dso->needs_swap == DSO_SWAP__UNSET); \
197 if (dso->needs_swap == DSO_SWAP__YES) { \
198 switch (sizeof(____r)) { \
199 case 2: \
200 ____r = bswap_16(val); \
201 break; \
202 case 4: \
203 ____r = bswap_32(val); \
204 break; \
205 case 8: \
206 ____r = bswap_64(val); \
207 break; \
208 default: \
209 BUG_ON(1); \
210 } \
211 } \
212 ____r; \
213})
214
180struct dso *dso__new(const char *name); 215struct dso *dso__new(const char *name);
181void dso__delete(struct dso *dso); 216void dso__delete(struct dso *dso);
182 217
@@ -237,6 +272,7 @@ void dso__set_long_name(struct dso *dso, char *name);
237void dso__set_build_id(struct dso *dso, void *build_id); 272void dso__set_build_id(struct dso *dso, void *build_id);
238void dso__read_running_kernel_build_id(struct dso *dso, 273void dso__read_running_kernel_build_id(struct dso *dso,
239 struct machine *machine); 274 struct machine *machine);
275struct map *dso__new_map(const char *name);
240struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, 276struct symbol *dso__find_symbol(struct dso *dso, enum map_type type,
241 u64 addr); 277 u64 addr);
242struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, 278struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type,
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c
new file mode 100644
index 000000000000..1064d5b148ad
--- /dev/null
+++ b/tools/perf/util/target.c
@@ -0,0 +1,142 @@
1/*
2 * Helper functions for handling target threads/cpus
3 *
4 * Copyright (C) 2012, LG Electronics, Namhyung Kim <namhyung.kim@lge.com>
5 *
6 * Released under the GPL v2.
7 */
8
9#include "target.h"
10#include "debug.h"
11
12#include <pwd.h>
13#include <string.h>
14
15
16enum perf_target_errno perf_target__validate(struct perf_target *target)
17{
18 enum perf_target_errno ret = PERF_ERRNO_TARGET__SUCCESS;
19
20 if (target->pid)
21 target->tid = target->pid;
22
23 /* CPU and PID are mutually exclusive */
24 if (target->tid && target->cpu_list) {
25 target->cpu_list = NULL;
26 if (ret == PERF_ERRNO_TARGET__SUCCESS)
27 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_CPU;
28 }
29
30 /* UID and PID are mutually exclusive */
31 if (target->tid && target->uid_str) {
32 target->uid_str = NULL;
33 if (ret == PERF_ERRNO_TARGET__SUCCESS)
34 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_UID;
35 }
36
37 /* UID and CPU are mutually exclusive */
38 if (target->uid_str && target->cpu_list) {
39 target->cpu_list = NULL;
40 if (ret == PERF_ERRNO_TARGET__SUCCESS)
41 ret = PERF_ERRNO_TARGET__UID_OVERRIDE_CPU;
42 }
43
44 /* PID and SYSTEM are mutually exclusive */
45 if (target->tid && target->system_wide) {
46 target->system_wide = false;
47 if (ret == PERF_ERRNO_TARGET__SUCCESS)
48 ret = PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM;
49 }
50
51 /* UID and SYSTEM are mutually exclusive */
52 if (target->uid_str && target->system_wide) {
53 target->system_wide = false;
54 if (ret == PERF_ERRNO_TARGET__SUCCESS)
55 ret = PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM;
56 }
57
58 return ret;
59}
60
61enum perf_target_errno perf_target__parse_uid(struct perf_target *target)
62{
63 struct passwd pwd, *result;
64 char buf[1024];
65 const char *str = target->uid_str;
66
67 target->uid = UINT_MAX;
68 if (str == NULL)
69 return PERF_ERRNO_TARGET__SUCCESS;
70
71 /* Try user name first */
72 getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
73
74 if (result == NULL) {
75 /*
76 * The user name not found. Maybe it's a UID number.
77 */
78 char *endptr;
79 int uid = strtol(str, &endptr, 10);
80
81 if (*endptr != '\0')
82 return PERF_ERRNO_TARGET__INVALID_UID;
83
84 getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
85
86 if (result == NULL)
87 return PERF_ERRNO_TARGET__USER_NOT_FOUND;
88 }
89
90 target->uid = result->pw_uid;
91 return PERF_ERRNO_TARGET__SUCCESS;
92}
93
94/*
95 * This must have a same ordering as the enum perf_target_errno.
96 */
97static const char *perf_target__error_str[] = {
98 "PID/TID switch overriding CPU",
99 "PID/TID switch overriding UID",
100 "UID switch overriding CPU",
101 "PID/TID switch overriding SYSTEM",
102 "UID switch overriding SYSTEM",
103 "Invalid User: %s",
104 "Problems obtaining information for user %s",
105};
106
107int perf_target__strerror(struct perf_target *target, int errnum,
108 char *buf, size_t buflen)
109{
110 int idx;
111 const char *msg;
112
113 if (errnum >= 0) {
114 strerror_r(errnum, buf, buflen);
115 return 0;
116 }
117
118 if (errnum < __PERF_ERRNO_TARGET__START ||
119 errnum >= __PERF_ERRNO_TARGET__END)
120 return -1;
121
122 idx = errnum - __PERF_ERRNO_TARGET__START;
123 msg = perf_target__error_str[idx];
124
125 switch (errnum) {
126 case PERF_ERRNO_TARGET__PID_OVERRIDE_CPU
127 ... PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM:
128 snprintf(buf, buflen, "%s", msg);
129 break;
130
131 case PERF_ERRNO_TARGET__INVALID_UID:
132 case PERF_ERRNO_TARGET__USER_NOT_FOUND:
133 snprintf(buf, buflen, msg, target->uid_str);
134 break;
135
136 default:
137 /* cannot reach here */
138 break;
139 }
140
141 return 0;
142}
diff --git a/tools/perf/util/target.h b/tools/perf/util/target.h
new file mode 100644
index 000000000000..a4be8575fda5
--- /dev/null
+++ b/tools/perf/util/target.h
@@ -0,0 +1,65 @@
1#ifndef _PERF_TARGET_H
2#define _PERF_TARGET_H
3
4#include <stdbool.h>
5#include <sys/types.h>
6
7struct perf_target {
8 const char *pid;
9 const char *tid;
10 const char *cpu_list;
11 const char *uid_str;
12 uid_t uid;
13 bool system_wide;
14 bool uses_mmap;
15};
16
17enum perf_target_errno {
18 PERF_ERRNO_TARGET__SUCCESS = 0,
19
20 /*
21 * Choose an arbitrary negative big number not to clash with standard
22 * errno since SUS requires the errno has distinct positive values.
23 * See 'Issue 6' in the link below.
24 *
25 * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
26 */
27 __PERF_ERRNO_TARGET__START = -10000,
28
29
30 /* for perf_target__validate() */
31 PERF_ERRNO_TARGET__PID_OVERRIDE_CPU = __PERF_ERRNO_TARGET__START,
32 PERF_ERRNO_TARGET__PID_OVERRIDE_UID,
33 PERF_ERRNO_TARGET__UID_OVERRIDE_CPU,
34 PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM,
35 PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM,
36
37 /* for perf_target__parse_uid() */
38 PERF_ERRNO_TARGET__INVALID_UID,
39 PERF_ERRNO_TARGET__USER_NOT_FOUND,
40
41 __PERF_ERRNO_TARGET__END,
42};
43
44enum perf_target_errno perf_target__validate(struct perf_target *target);
45enum perf_target_errno perf_target__parse_uid(struct perf_target *target);
46
47int perf_target__strerror(struct perf_target *target, int errnum, char *buf,
48 size_t buflen);
49
50static inline bool perf_target__has_task(struct perf_target *target)
51{
52 return target->tid || target->pid || target->uid_str;
53}
54
55static inline bool perf_target__has_cpu(struct perf_target *target)
56{
57 return target->system_wide || target->cpu_list;
58}
59
60static inline bool perf_target__none(struct perf_target *target)
61{
62 return !perf_target__has_task(target) && !perf_target__has_cpu(target);
63}
64
65#endif /* _PERF_TARGET_H */
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 84d9bd782004..9b5f856cc280 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -188,28 +188,27 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
188 nt = realloc(threads, (sizeof(*threads) + 188 nt = realloc(threads, (sizeof(*threads) +
189 sizeof(pid_t) * total_tasks)); 189 sizeof(pid_t) * total_tasks));
190 if (nt == NULL) 190 if (nt == NULL)
191 goto out_free_threads; 191 goto out_free_namelist;
192 192
193 threads = nt; 193 threads = nt;
194 194
195 if (threads) { 195 for (i = 0; i < items; i++) {
196 for (i = 0; i < items; i++) 196 threads->map[j++] = atoi(namelist[i]->d_name);
197 threads->map[j++] = atoi(namelist[i]->d_name);
198 threads->nr = total_tasks;
199 }
200
201 for (i = 0; i < items; i++)
202 free(namelist[i]); 197 free(namelist[i]);
198 }
199 threads->nr = total_tasks;
203 free(namelist); 200 free(namelist);
204
205 if (!threads)
206 break;
207 } 201 }
208 202
209out: 203out:
210 strlist__delete(slist); 204 strlist__delete(slist);
211 return threads; 205 return threads;
212 206
207out_free_namelist:
208 for (i = 0; i < items; i++)
209 free(namelist[i]);
210 free(namelist);
211
213out_free_threads: 212out_free_threads:
214 free(threads); 213 free(threads);
215 threads = NULL; 214 threads = NULL;
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index 7da80f14418b..f718df8a3c59 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -6,7 +6,7 @@
6 6
7struct thread_map { 7struct thread_map {
8 int nr; 8 int nr;
9 int map[]; 9 pid_t map[];
10}; 10};
11 11
12struct thread_map *thread_map__new_by_pid(pid_t pid); 12struct thread_map *thread_map__new_by_pid(pid_t pid);
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index 09fe579ccafb..abe0e8e95068 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -69,23 +69,24 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
69 69
70 ret += SNPRINTF(bf + ret, size - ret, "], "); 70 ret += SNPRINTF(bf + ret, size - ret, "], ");
71 71
72 if (top->target_pid) 72 if (top->target.pid)
73 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", 73 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
74 top->target_pid); 74 top->target.pid);
75 else if (top->target_tid) 75 else if (top->target.tid)
76 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", 76 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
77 top->target_tid); 77 top->target.tid);
78 else if (top->uid_str != NULL) 78 else if (top->target.uid_str != NULL)
79 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", 79 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
80 top->uid_str); 80 top->target.uid_str);
81 else 81 else
82 ret += SNPRINTF(bf + ret, size - ret, " (all"); 82 ret += SNPRINTF(bf + ret, size - ret, " (all");
83 83
84 if (top->cpu_list) 84 if (top->target.cpu_list)
85 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", 85 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
86 top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list); 86 top->evlist->cpus->nr > 1 ? "s" : "",
87 top->target.cpu_list);
87 else { 88 else {
88 if (top->target_tid) 89 if (top->target.tid)
89 ret += SNPRINTF(bf + ret, size - ret, ")"); 90 ret += SNPRINTF(bf + ret, size - ret, ")");
90 else 91 else
91 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", 92 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index ce61cb2d1acf..33347ca89ee4 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -13,6 +13,7 @@ struct perf_session;
13struct perf_top { 13struct perf_top {
14 struct perf_tool tool; 14 struct perf_tool tool;
15 struct perf_evlist *evlist; 15 struct perf_evlist *evlist;
16 struct perf_target target;
16 /* 17 /*
17 * Symbols will be added here in perf_event__process_sample and will 18 * Symbols will be added here in perf_event__process_sample and will
18 * get out after decayed. 19 * get out after decayed.
@@ -23,10 +24,7 @@ struct perf_top {
23 u64 guest_us_samples, guest_kernel_samples; 24 u64 guest_us_samples, guest_kernel_samples;
24 int print_entries, count_filter, delay_secs; 25 int print_entries, count_filter, delay_secs;
25 int freq; 26 int freq;
26 const char *target_pid, *target_tid;
27 uid_t uid;
28 bool hide_kernel_symbols, hide_user_symbols, zero; 27 bool hide_kernel_symbols, hide_user_symbols, zero;
29 bool system_wide;
30 bool use_tui, use_stdio; 28 bool use_tui, use_stdio;
31 bool sort_has_symbols; 29 bool sort_has_symbols;
32 bool dont_use_callchains; 30 bool dont_use_callchains;
@@ -37,7 +35,6 @@ struct perf_top {
37 bool sample_id_all_missing; 35 bool sample_id_all_missing;
38 bool exclude_guest_missing; 36 bool exclude_guest_missing;
39 bool dump_symtab; 37 bool dump_symtab;
40 const char *cpu_list;
41 struct hist_entry *sym_filter_entry; 38 struct hist_entry *sym_filter_entry;
42 struct perf_evsel *sym_evsel; 39 struct perf_evsel *sym_evsel;
43 struct perf_session *session; 40 struct perf_session *session;
@@ -47,7 +44,6 @@ struct perf_top {
47 int realtime_prio; 44 int realtime_prio;
48 int sym_pcnt_filter; 45 int sym_pcnt_filter;
49 const char *sym_filter; 46 const char *sym_filter;
50 const char *uid_str;
51}; 47};
52 48
53size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 49size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index fc22cf5c605f..a8d81c35ef66 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -68,7 +68,7 @@ struct events {
68}; 68};
69 69
70 70
71void *malloc_or_die(unsigned int size) 71static void *malloc_or_die(unsigned int size)
72{ 72{
73 void *data; 73 void *data;
74 74
@@ -448,6 +448,8 @@ static void tracing_data_header(void)
448 else 448 else
449 buf[0] = 0; 449 buf[0] = 0;
450 450
451 read_trace_init(buf[0], buf[0]);
452
451 write_or_die(buf, 1); 453 write_or_die(buf, 1);
452 454
453 /* save size of long */ 455 /* save size of long */
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index dfd1bd8371a4..df2fddbf0cd2 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -17,2169 +17,305 @@
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * 18 *
19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
20 *
21 * The parts for function graph printing was taken and modified from the
22 * Linux Kernel that were written by Frederic Weisbecker.
23 */ 20 */
24
25#include <stdio.h> 21#include <stdio.h>
26#include <stdlib.h> 22#include <stdlib.h>
27#include <string.h> 23#include <string.h>
24#include <ctype.h>
28#include <errno.h> 25#include <errno.h>
29 26
30#include "../perf.h" 27#include "../perf.h"
31#include "util.h" 28#include "util.h"
32#include "trace-event.h" 29#include "trace-event.h"
33 30
34int header_page_ts_offset;
35int header_page_ts_size;
36int header_page_size_offset;
37int header_page_size_size; 31int header_page_size_size;
38int header_page_overwrite_offset; 32int header_page_ts_size;
39int header_page_overwrite_size;
40int header_page_data_offset; 33int header_page_data_offset;
41int header_page_data_size;
42
43bool latency_format;
44
45static char *input_buf;
46static unsigned long long input_buf_ptr;
47static unsigned long long input_buf_siz;
48
49static int cpus;
50static int long_size;
51static int is_flag_field;
52static int is_symbolic_field;
53
54static struct format_field *
55find_any_field(struct event *event, const char *name);
56
57static void init_input_buf(char *buf, unsigned long long size)
58{
59 input_buf = buf;
60 input_buf_siz = size;
61 input_buf_ptr = 0;
62}
63
64struct cmdline {
65 char *comm;
66 int pid;
67};
68
69static struct cmdline *cmdlines;
70static int cmdline_count;
71
72static int cmdline_cmp(const void *a, const void *b)
73{
74 const struct cmdline *ca = a;
75 const struct cmdline *cb = b;
76
77 if (ca->pid < cb->pid)
78 return -1;
79 if (ca->pid > cb->pid)
80 return 1;
81
82 return 0;
83}
84 34
85void parse_cmdlines(char *file, int size __unused) 35struct pevent *perf_pevent;
86{ 36static struct pevent *pevent;
87 struct cmdline_list {
88 struct cmdline_list *next;
89 char *comm;
90 int pid;
91 } *list = NULL, *item;
92 char *line;
93 char *next = NULL;
94 int i;
95 37
96 line = strtok_r(file, "\n", &next); 38bool latency_format;
97 while (line) {
98 item = malloc_or_die(sizeof(*item));
99 sscanf(line, "%d %as", &item->pid,
100 (float *)(void *)&item->comm); /* workaround gcc warning */
101 item->next = list;
102 list = item;
103 line = strtok_r(NULL, "\n", &next);
104 cmdline_count++;
105 }
106
107 cmdlines = malloc_or_die(sizeof(*cmdlines) * cmdline_count);
108
109 i = 0;
110 while (list) {
111 cmdlines[i].pid = list->pid;
112 cmdlines[i].comm = list->comm;
113 i++;
114 item = list;
115 list = list->next;
116 free(item);
117 }
118
119 qsort(cmdlines, cmdline_count, sizeof(*cmdlines), cmdline_cmp);
120}
121
122static struct func_map {
123 unsigned long long addr;
124 char *func;
125 char *mod;
126} *func_list;
127static unsigned int func_count;
128
129static int func_cmp(const void *a, const void *b)
130{
131 const struct func_map *fa = a;
132 const struct func_map *fb = b;
133
134 if (fa->addr < fb->addr)
135 return -1;
136 if (fa->addr > fb->addr)
137 return 1;
138
139 return 0;
140}
141
142void parse_proc_kallsyms(char *file, unsigned int size __unused)
143{
144 struct func_list {
145 struct func_list *next;
146 unsigned long long addr;
147 char *func;
148 char *mod;
149 } *list = NULL, *item;
150 char *line;
151 char *next = NULL;
152 char *addr_str;
153 char ch;
154 int ret __used;
155 int i;
156
157 line = strtok_r(file, "\n", &next);
158 while (line) {
159 item = malloc_or_die(sizeof(*item));
160 item->mod = NULL;
161 ret = sscanf(line, "%as %c %as\t[%as",
162 (float *)(void *)&addr_str, /* workaround gcc warning */
163 &ch,
164 (float *)(void *)&item->func,
165 (float *)(void *)&item->mod);
166 item->addr = strtoull(addr_str, NULL, 16);
167 free(addr_str);
168
169 /* truncate the extra ']' */
170 if (item->mod)
171 item->mod[strlen(item->mod) - 1] = 0;
172
173
174 item->next = list;
175 list = item;
176 line = strtok_r(NULL, "\n", &next);
177 func_count++;
178 }
179
180 func_list = malloc_or_die(sizeof(*func_list) * (func_count + 1));
181
182 i = 0;
183 while (list) {
184 func_list[i].func = list->func;
185 func_list[i].addr = list->addr;
186 func_list[i].mod = list->mod;
187 i++;
188 item = list;
189 list = list->next;
190 free(item);
191 }
192
193 qsort(func_list, func_count, sizeof(*func_list), func_cmp);
194
195 /*
196 * Add a special record at the end.
197 */
198 func_list[func_count].func = NULL;
199 func_list[func_count].addr = 0;
200 func_list[func_count].mod = NULL;
201}
202 39
203/* 40int read_trace_init(int file_bigendian, int host_bigendian)
204 * We are searching for a record in between, not an exact
205 * match.
206 */
207static int func_bcmp(const void *a, const void *b)
208{ 41{
209 const struct func_map *fa = a; 42 if (pevent)
210 const struct func_map *fb = b;
211
212 if ((fa->addr == fb->addr) ||
213
214 (fa->addr > fb->addr &&
215 fa->addr < (fb+1)->addr))
216 return 0; 43 return 0;
217 44
218 if (fa->addr < fb->addr) 45 perf_pevent = pevent_alloc();
219 return -1; 46 pevent = perf_pevent;
220
221 return 1;
222}
223
224static struct func_map *find_func(unsigned long long addr)
225{
226 struct func_map *func;
227 struct func_map key;
228
229 key.addr = addr;
230
231 func = bsearch(&key, func_list, func_count, sizeof(*func_list),
232 func_bcmp);
233
234 return func;
235}
236
237void print_funcs(void)
238{
239 int i;
240
241 for (i = 0; i < (int)func_count; i++) {
242 printf("%016llx %s",
243 func_list[i].addr,
244 func_list[i].func);
245 if (func_list[i].mod)
246 printf(" [%s]\n", func_list[i].mod);
247 else
248 printf("\n");
249 }
250}
251 47
252static struct printk_map { 48 pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
253 unsigned long long addr; 49 pevent_set_file_bigendian(pevent, file_bigendian);
254 char *printk; 50 pevent_set_host_bigendian(pevent, host_bigendian);
255} *printk_list;
256static unsigned int printk_count;
257
258static int printk_cmp(const void *a, const void *b)
259{
260 const struct func_map *fa = a;
261 const struct func_map *fb = b;
262
263 if (fa->addr < fb->addr)
264 return -1;
265 if (fa->addr > fb->addr)
266 return 1;
267 51
268 return 0; 52 return 0;
269} 53}
270 54
271static struct printk_map *find_printk(unsigned long long addr) 55static int get_common_field(struct scripting_context *context,
272{ 56 int *offset, int *size, const char *type)
273 struct printk_map *printk;
274 struct printk_map key;
275
276 key.addr = addr;
277
278 printk = bsearch(&key, printk_list, printk_count, sizeof(*printk_list),
279 printk_cmp);
280
281 return printk;
282}
283
284void parse_ftrace_printk(char *file, unsigned int size __unused)
285{
286 struct printk_list {
287 struct printk_list *next;
288 unsigned long long addr;
289 char *printk;
290 } *list = NULL, *item;
291 char *line;
292 char *next = NULL;
293 char *addr_str;
294 int i;
295
296 line = strtok_r(file, "\n", &next);
297 while (line) {
298 addr_str = strsep(&line, ":");
299 if (!line) {
300 warning("error parsing print strings");
301 break;
302 }
303 item = malloc_or_die(sizeof(*item));
304 item->addr = strtoull(addr_str, NULL, 16);
305 /* fmt still has a space, skip it */
306 item->printk = strdup(line+1);
307 item->next = list;
308 list = item;
309 line = strtok_r(NULL, "\n", &next);
310 printk_count++;
311 }
312
313 printk_list = malloc_or_die(sizeof(*printk_list) * printk_count + 1);
314
315 i = 0;
316 while (list) {
317 printk_list[i].printk = list->printk;
318 printk_list[i].addr = list->addr;
319 i++;
320 item = list;
321 list = list->next;
322 free(item);
323 }
324
325 qsort(printk_list, printk_count, sizeof(*printk_list), printk_cmp);
326}
327
328void print_printk(void)
329{
330 int i;
331
332 for (i = 0; i < (int)printk_count; i++) {
333 printf("%016llx %s\n",
334 printk_list[i].addr,
335 printk_list[i].printk);
336 }
337}
338
339static struct event *alloc_event(void)
340{
341 struct event *event;
342
343 event = malloc_or_die(sizeof(*event));
344 memset(event, 0, sizeof(*event));
345
346 return event;
347}
348
349enum event_type {
350 EVENT_ERROR,
351 EVENT_NONE,
352 EVENT_SPACE,
353 EVENT_NEWLINE,
354 EVENT_OP,
355 EVENT_DELIM,
356 EVENT_ITEM,
357 EVENT_DQUOTE,
358 EVENT_SQUOTE,
359};
360
361static struct event *event_list;
362
363static void add_event(struct event *event)
364{ 57{
365 event->next = event_list; 58 struct event_format *event;
366 event_list = event; 59 struct format_field *field;
367}
368
369static int event_item_type(enum event_type type)
370{
371 switch (type) {
372 case EVENT_ITEM ... EVENT_SQUOTE:
373 return 1;
374 case EVENT_ERROR ... EVENT_DELIM:
375 default:
376 return 0;
377 }
378}
379
380static void free_arg(struct print_arg *arg)
381{
382 if (!arg)
383 return;
384
385 switch (arg->type) {
386 case PRINT_ATOM:
387 if (arg->atom.atom)
388 free(arg->atom.atom);
389 break;
390 case PRINT_NULL:
391 case PRINT_FIELD ... PRINT_OP:
392 default:
393 /* todo */
394 break;
395 }
396
397 free(arg);
398}
399
400static enum event_type get_type(int ch)
401{
402 if (ch == '\n')
403 return EVENT_NEWLINE;
404 if (isspace(ch))
405 return EVENT_SPACE;
406 if (isalnum(ch) || ch == '_')
407 return EVENT_ITEM;
408 if (ch == '\'')
409 return EVENT_SQUOTE;
410 if (ch == '"')
411 return EVENT_DQUOTE;
412 if (!isprint(ch))
413 return EVENT_NONE;
414 if (ch == '(' || ch == ')' || ch == ',')
415 return EVENT_DELIM;
416
417 return EVENT_OP;
418}
419
420static int __read_char(void)
421{
422 if (input_buf_ptr >= input_buf_siz)
423 return -1;
424
425 return input_buf[input_buf_ptr++];
426}
427
428static int __peek_char(void)
429{
430 if (input_buf_ptr >= input_buf_siz)
431 return -1;
432
433 return input_buf[input_buf_ptr];
434}
435
436static enum event_type __read_token(char **tok)
437{
438 char buf[BUFSIZ];
439 int ch, last_ch, quote_ch, next_ch;
440 int i = 0;
441 int tok_size = 0;
442 enum event_type type;
443
444 *tok = NULL;
445
446
447 ch = __read_char();
448 if (ch < 0)
449 return EVENT_NONE;
450
451 type = get_type(ch);
452 if (type == EVENT_NONE)
453 return type;
454
455 buf[i++] = ch;
456
457 switch (type) {
458 case EVENT_NEWLINE:
459 case EVENT_DELIM:
460 *tok = malloc_or_die(2);
461 (*tok)[0] = ch;
462 (*tok)[1] = 0;
463 return type;
464
465 case EVENT_OP:
466 switch (ch) {
467 case '-':
468 next_ch = __peek_char();
469 if (next_ch == '>') {
470 buf[i++] = __read_char();
471 break;
472 }
473 /* fall through */
474 case '+':
475 case '|':
476 case '&':
477 case '>':
478 case '<':
479 last_ch = ch;
480 ch = __peek_char();
481 if (ch != last_ch)
482 goto test_equal;
483 buf[i++] = __read_char();
484 switch (last_ch) {
485 case '>':
486 case '<':
487 goto test_equal;
488 default:
489 break;
490 }
491 break;
492 case '!':
493 case '=':
494 goto test_equal;
495 default: /* what should we do instead? */
496 break;
497 }
498 buf[i] = 0;
499 *tok = strdup(buf);
500 return type;
501
502 test_equal:
503 ch = __peek_char();
504 if (ch == '=')
505 buf[i++] = __read_char();
506 break;
507
508 case EVENT_DQUOTE:
509 case EVENT_SQUOTE:
510 /* don't keep quotes */
511 i--;
512 quote_ch = ch;
513 last_ch = 0;
514 do {
515 if (i == (BUFSIZ - 1)) {
516 buf[i] = 0;
517 if (*tok) {
518 *tok = realloc(*tok, tok_size + BUFSIZ);
519 if (!*tok)
520 return EVENT_NONE;
521 strcat(*tok, buf);
522 } else
523 *tok = strdup(buf);
524
525 if (!*tok)
526 return EVENT_NONE;
527 tok_size += BUFSIZ;
528 i = 0;
529 }
530 last_ch = ch;
531 ch = __read_char();
532 buf[i++] = ch;
533 /* the '\' '\' will cancel itself */
534 if (ch == '\\' && last_ch == '\\')
535 last_ch = 0;
536 } while (ch != quote_ch || last_ch == '\\');
537 /* remove the last quote */
538 i--;
539 goto out;
540
541 case EVENT_ERROR ... EVENT_SPACE:
542 case EVENT_ITEM:
543 default:
544 break;
545 }
546
547 while (get_type(__peek_char()) == type) {
548 if (i == (BUFSIZ - 1)) {
549 buf[i] = 0;
550 if (*tok) {
551 *tok = realloc(*tok, tok_size + BUFSIZ);
552 if (!*tok)
553 return EVENT_NONE;
554 strcat(*tok, buf);
555 } else
556 *tok = strdup(buf);
557
558 if (!*tok)
559 return EVENT_NONE;
560 tok_size += BUFSIZ;
561 i = 0;
562 }
563 ch = __read_char();
564 buf[i++] = ch;
565 }
566
567 out:
568 buf[i] = 0;
569 if (*tok) {
570 *tok = realloc(*tok, tok_size + i);
571 if (!*tok)
572 return EVENT_NONE;
573 strcat(*tok, buf);
574 } else
575 *tok = strdup(buf);
576 if (!*tok)
577 return EVENT_NONE;
578
579 return type;
580}
581
582static void free_token(char *tok)
583{
584 if (tok)
585 free(tok);
586}
587
588static enum event_type read_token(char **tok)
589{
590 enum event_type type;
591
592 for (;;) {
593 type = __read_token(tok);
594 if (type != EVENT_SPACE)
595 return type;
596
597 free_token(*tok);
598 }
599
600 /* not reached */
601 return EVENT_NONE;
602}
603
604/* no newline */
605static enum event_type read_token_item(char **tok)
606{
607 enum event_type type;
608
609 for (;;) {
610 type = __read_token(tok);
611 if (type != EVENT_SPACE && type != EVENT_NEWLINE)
612 return type;
613
614 free_token(*tok);
615 }
616
617 /* not reached */
618 return EVENT_NONE;
619}
620
621static int test_type(enum event_type type, enum event_type expect)
622{
623 if (type != expect) {
624 warning("Error: expected type %d but read %d",
625 expect, type);
626 return -1;
627 }
628 return 0;
629}
630 60
631static int __test_type_token(enum event_type type, char *token, 61 if (!*size) {
632 enum event_type expect, const char *expect_tok, 62 if (!pevent->events)
633 bool warn) 63 return 0;
634{
635 if (type != expect) {
636 if (warn)
637 warning("Error: expected type %d but read %d",
638 expect, type);
639 return -1;
640 }
641 64
642 if (strcmp(token, expect_tok) != 0) { 65 event = pevent->events[0];
643 if (warn) 66 field = pevent_find_common_field(event, type);
644 warning("Error: expected '%s' but read '%s'", 67 if (!field)
645 expect_tok, token); 68 return 0;
646 return -1; 69 *offset = field->offset;
70 *size = field->size;
647 } 71 }
648 return 0;
649}
650 72
651static int test_type_token(enum event_type type, char *token, 73 return pevent_read_number(pevent, context->event_data + *offset, *size);
652 enum event_type expect, const char *expect_tok)
653{
654 return __test_type_token(type, token, expect, expect_tok, true);
655} 74}
656 75
657static int __read_expect_type(enum event_type expect, char **tok, int newline_ok) 76int common_lock_depth(struct scripting_context *context)
658{
659 enum event_type type;
660
661 if (newline_ok)
662 type = read_token(tok);
663 else
664 type = read_token_item(tok);
665 return test_type(type, expect);
666}
667
668static int read_expect_type(enum event_type expect, char **tok)
669{
670 return __read_expect_type(expect, tok, 1);
671}
672
673static int __read_expected(enum event_type expect, const char *str,
674 int newline_ok, bool warn)
675{ 77{
676 enum event_type type; 78 static int offset;
677 char *token; 79 static int size;
678 int ret; 80 int ret;
679 81
680 if (newline_ok) 82 ret = get_common_field(context, &size, &offset,
681 type = read_token(&token); 83 "common_lock_depth");
682 else 84 if (ret < 0)
683 type = read_token_item(&token); 85 return -1;
684
685 ret = __test_type_token(type, token, expect, str, warn);
686
687 free_token(token);
688 86
689 return ret; 87 return ret;
690} 88}
691 89
692static int read_expected(enum event_type expect, const char *str) 90int common_flags(struct scripting_context *context)
693{
694 return __read_expected(expect, str, 1, true);
695}
696
697static int read_expected_item(enum event_type expect, const char *str)
698{
699 return __read_expected(expect, str, 0, true);
700}
701
702static char *event_read_name(void)
703{
704 char *token;
705
706 if (read_expected(EVENT_ITEM, "name") < 0)
707 return NULL;
708
709 if (read_expected(EVENT_OP, ":") < 0)
710 return NULL;
711
712 if (read_expect_type(EVENT_ITEM, &token) < 0)
713 goto fail;
714
715 return token;
716
717 fail:
718 free_token(token);
719 return NULL;
720}
721
722static int event_read_id(void)
723{ 91{
724 char *token; 92 static int offset;
725 int id = -1; 93 static int size;
726 94 int ret;
727 if (read_expected_item(EVENT_ITEM, "ID") < 0)
728 return -1;
729 95
730 if (read_expected(EVENT_OP, ":") < 0) 96 ret = get_common_field(context, &size, &offset,
97 "common_flags");
98 if (ret < 0)
731 return -1; 99 return -1;
732 100
733 if (read_expect_type(EVENT_ITEM, &token) < 0) 101 return ret;
734 goto free;
735
736 id = strtoul(token, NULL, 0);
737
738 free:
739 free_token(token);
740 return id;
741}
742
743static int field_is_string(struct format_field *field)
744{
745 if ((field->flags & FIELD_IS_ARRAY) &&
746 (!strstr(field->type, "char") || !strstr(field->type, "u8") ||
747 !strstr(field->type, "s8")))
748 return 1;
749
750 return 0;
751}
752
753static int field_is_dynamic(struct format_field *field)
754{
755 if (!strncmp(field->type, "__data_loc", 10))
756 return 1;
757
758 return 0;
759}
760
761static int event_read_fields(struct event *event, struct format_field **fields)
762{
763 struct format_field *field = NULL;
764 enum event_type type;
765 char *token;
766 char *last_token;
767 int count = 0;
768
769 do {
770 type = read_token(&token);
771 if (type == EVENT_NEWLINE) {
772 free_token(token);
773 return count;
774 }
775
776 count++;
777
778 if (test_type_token(type, token, EVENT_ITEM, "field"))
779 goto fail;
780 free_token(token);
781
782 type = read_token(&token);
783 /*
784 * The ftrace fields may still use the "special" name.
785 * Just ignore it.
786 */
787 if (event->flags & EVENT_FL_ISFTRACE &&
788 type == EVENT_ITEM && strcmp(token, "special") == 0) {
789 free_token(token);
790 type = read_token(&token);
791 }
792
793 if (test_type_token(type, token, EVENT_OP, ":") < 0)
794 return -1;
795
796 if (read_expect_type(EVENT_ITEM, &token) < 0)
797 goto fail;
798
799 last_token = token;
800
801 field = malloc_or_die(sizeof(*field));
802 memset(field, 0, sizeof(*field));
803
804 /* read the rest of the type */
805 for (;;) {
806 type = read_token(&token);
807 if (type == EVENT_ITEM ||
808 (type == EVENT_OP && strcmp(token, "*") == 0) ||
809 /*
810 * Some of the ftrace fields are broken and have
811 * an illegal "." in them.
812 */
813 (event->flags & EVENT_FL_ISFTRACE &&
814 type == EVENT_OP && strcmp(token, ".") == 0)) {
815
816 if (strcmp(token, "*") == 0)
817 field->flags |= FIELD_IS_POINTER;
818
819 if (field->type) {
820 field->type = realloc(field->type,
821 strlen(field->type) +
822 strlen(last_token) + 2);
823 strcat(field->type, " ");
824 strcat(field->type, last_token);
825 } else
826 field->type = last_token;
827 last_token = token;
828 continue;
829 }
830
831 break;
832 }
833
834 if (!field->type) {
835 die("no type found");
836 goto fail;
837 }
838 field->name = last_token;
839
840 if (test_type(type, EVENT_OP))
841 goto fail;
842
843 if (strcmp(token, "[") == 0) {
844 enum event_type last_type = type;
845 char *brackets = token;
846 int len;
847
848 field->flags |= FIELD_IS_ARRAY;
849
850 type = read_token(&token);
851 while (strcmp(token, "]") != 0) {
852 if (last_type == EVENT_ITEM &&
853 type == EVENT_ITEM)
854 len = 2;
855 else
856 len = 1;
857 last_type = type;
858
859 brackets = realloc(brackets,
860 strlen(brackets) +
861 strlen(token) + len);
862 if (len == 2)
863 strcat(brackets, " ");
864 strcat(brackets, token);
865 free_token(token);
866 type = read_token(&token);
867 if (type == EVENT_NONE) {
868 die("failed to find token");
869 goto fail;
870 }
871 }
872
873 free_token(token);
874
875 brackets = realloc(brackets, strlen(brackets) + 2);
876 strcat(brackets, "]");
877
878 /* add brackets to type */
879
880 type = read_token(&token);
881 /*
882 * If the next token is not an OP, then it is of
883 * the format: type [] item;
884 */
885 if (type == EVENT_ITEM) {
886 field->type = realloc(field->type,
887 strlen(field->type) +
888 strlen(field->name) +
889 strlen(brackets) + 2);
890 strcat(field->type, " ");
891 strcat(field->type, field->name);
892 free_token(field->name);
893 strcat(field->type, brackets);
894 field->name = token;
895 type = read_token(&token);
896 } else {
897 field->type = realloc(field->type,
898 strlen(field->type) +
899 strlen(brackets) + 1);
900 strcat(field->type, brackets);
901 }
902 free(brackets);
903 }
904
905 if (field_is_string(field)) {
906 field->flags |= FIELD_IS_STRING;
907 if (field_is_dynamic(field))
908 field->flags |= FIELD_IS_DYNAMIC;
909 }
910
911 if (test_type_token(type, token, EVENT_OP, ";"))
912 goto fail;
913 free_token(token);
914
915 if (read_expected(EVENT_ITEM, "offset") < 0)
916 goto fail_expect;
917
918 if (read_expected(EVENT_OP, ":") < 0)
919 goto fail_expect;
920
921 if (read_expect_type(EVENT_ITEM, &token))
922 goto fail;
923 field->offset = strtoul(token, NULL, 0);
924 free_token(token);
925
926 if (read_expected(EVENT_OP, ";") < 0)
927 goto fail_expect;
928
929 if (read_expected(EVENT_ITEM, "size") < 0)
930 goto fail_expect;
931
932 if (read_expected(EVENT_OP, ":") < 0)
933 goto fail_expect;
934
935 if (read_expect_type(EVENT_ITEM, &token))
936 goto fail;
937 field->size = strtoul(token, NULL, 0);
938 free_token(token);
939
940 if (read_expected(EVENT_OP, ";") < 0)
941 goto fail_expect;
942
943 type = read_token(&token);
944 if (type != EVENT_NEWLINE) {
945 /* newer versions of the kernel have a "signed" type */
946 if (test_type_token(type, token, EVENT_ITEM, "signed"))
947 goto fail;
948
949 free_token(token);
950
951 if (read_expected(EVENT_OP, ":") < 0)
952 goto fail_expect;
953
954 if (read_expect_type(EVENT_ITEM, &token))
955 goto fail;
956
957 if (strtoul(token, NULL, 0))
958 field->flags |= FIELD_IS_SIGNED;
959
960 free_token(token);
961 if (read_expected(EVENT_OP, ";") < 0)
962 goto fail_expect;
963
964 if (read_expect_type(EVENT_NEWLINE, &token))
965 goto fail;
966 }
967
968 free_token(token);
969
970 *fields = field;
971 fields = &field->next;
972
973 } while (1);
974
975 return 0;
976
977fail:
978 free_token(token);
979fail_expect:
980 if (field)
981 free(field);
982 return -1;
983} 102}
984 103
985static int event_read_format(struct event *event) 104int common_pc(struct scripting_context *context)
986{ 105{
987 char *token; 106 static int offset;
107 static int size;
988 int ret; 108 int ret;
989 109
990 if (read_expected_item(EVENT_ITEM, "format") < 0) 110 ret = get_common_field(context, &size, &offset,
991 return -1; 111 "common_preempt_count");
992
993 if (read_expected(EVENT_OP, ":") < 0)
994 return -1;
995
996 if (read_expect_type(EVENT_NEWLINE, &token))
997 goto fail;
998 free_token(token);
999
1000 ret = event_read_fields(event, &event->format.common_fields);
1001 if (ret < 0) 112 if (ret < 0)
1002 return ret; 113 return -1;
1003 event->format.nr_common = ret;
1004
1005 ret = event_read_fields(event, &event->format.fields);
1006 if (ret < 0)
1007 return ret;
1008 event->format.nr_fields = ret;
1009
1010 return 0;
1011
1012 fail:
1013 free_token(token);
1014 return -1;
1015}
1016
1017enum event_type
1018process_arg_token(struct event *event, struct print_arg *arg,
1019 char **tok, enum event_type type);
1020
1021static enum event_type
1022process_arg(struct event *event, struct print_arg *arg, char **tok)
1023{
1024 enum event_type type;
1025 char *token;
1026
1027 type = read_token(&token);
1028 *tok = token;
1029 114
1030 return process_arg_token(event, arg, tok, type); 115 return ret;
1031} 116}
1032 117
1033static enum event_type 118unsigned long long
1034process_cond(struct event *event, struct print_arg *top, char **tok) 119raw_field_value(struct event_format *event, const char *name, void *data)
1035{ 120{
1036 struct print_arg *arg, *left, *right; 121 struct format_field *field;
1037 enum event_type type; 122 unsigned long long val;
1038 char *token = NULL;
1039
1040 arg = malloc_or_die(sizeof(*arg));
1041 memset(arg, 0, sizeof(*arg));
1042
1043 left = malloc_or_die(sizeof(*left));
1044
1045 right = malloc_or_die(sizeof(*right));
1046
1047 arg->type = PRINT_OP;
1048 arg->op.left = left;
1049 arg->op.right = right;
1050
1051 *tok = NULL;
1052 type = process_arg(event, left, &token);
1053 if (test_type_token(type, token, EVENT_OP, ":"))
1054 goto out_free;
1055
1056 arg->op.op = token;
1057
1058 type = process_arg(event, right, &token);
1059 123
1060 top->op.right = arg; 124 field = pevent_find_any_field(event, name);
125 if (!field)
126 return 0ULL;
1061 127
1062 *tok = token; 128 pevent_read_number_field(field, data, &val);
1063 return type;
1064 129
1065out_free: 130 return val;
1066 free_token(*tok);
1067 free(right);
1068 free(left);
1069 free_arg(arg);
1070 return EVENT_ERROR;
1071} 131}
1072 132
1073static enum event_type 133void *raw_field_ptr(struct event_format *event, const char *name, void *data)
1074process_array(struct event *event, struct print_arg *top, char **tok)
1075{ 134{
1076 struct print_arg *arg; 135 struct format_field *field;
1077 enum event_type type;
1078 char *token = NULL;
1079
1080 arg = malloc_or_die(sizeof(*arg));
1081 memset(arg, 0, sizeof(*arg));
1082
1083 *tok = NULL;
1084 type = process_arg(event, arg, &token);
1085 if (test_type_token(type, token, EVENT_OP, "]"))
1086 goto out_free;
1087
1088 top->op.right = arg;
1089
1090 free_token(token);
1091 type = read_token_item(&token);
1092 *tok = token;
1093
1094 return type;
1095 136
1096out_free: 137 field = pevent_find_any_field(event, name);
1097 free_token(*tok); 138 if (!field)
1098 free_arg(arg); 139 return NULL;
1099 return EVENT_ERROR;
1100}
1101 140
1102static int get_op_prio(char *op) 141 if (field->flags & FIELD_IS_DYNAMIC) {
1103{ 142 int offset;
1104 if (!op[1]) {
1105 switch (op[0]) {
1106 case '*':
1107 case '/':
1108 case '%':
1109 return 6;
1110 case '+':
1111 case '-':
1112 return 7;
1113 /* '>>' and '<<' are 8 */
1114 case '<':
1115 case '>':
1116 return 9;
1117 /* '==' and '!=' are 10 */
1118 case '&':
1119 return 11;
1120 case '^':
1121 return 12;
1122 case '|':
1123 return 13;
1124 case '?':
1125 return 16;
1126 default:
1127 die("unknown op '%c'", op[0]);
1128 return -1;
1129 }
1130 } else {
1131 if (strcmp(op, "++") == 0 ||
1132 strcmp(op, "--") == 0) {
1133 return 3;
1134 } else if (strcmp(op, ">>") == 0 ||
1135 strcmp(op, "<<") == 0) {
1136 return 8;
1137 } else if (strcmp(op, ">=") == 0 ||
1138 strcmp(op, "<=") == 0) {
1139 return 9;
1140 } else if (strcmp(op, "==") == 0 ||
1141 strcmp(op, "!=") == 0) {
1142 return 10;
1143 } else if (strcmp(op, "&&") == 0) {
1144 return 14;
1145 } else if (strcmp(op, "||") == 0) {
1146 return 15;
1147 } else {
1148 die("unknown op '%s'", op);
1149 return -1;
1150 }
1151 }
1152}
1153 143
1154static void set_op_prio(struct print_arg *arg) 144 offset = *(int *)(data + field->offset);
1155{ 145 offset &= 0xffff;
1156 146
1157 /* single ops are the greatest */ 147 return data + offset;
1158 if (!arg->op.left || arg->op.left->type == PRINT_NULL) {
1159 arg->op.prio = 0;
1160 return;
1161 } 148 }
1162 149
1163 arg->op.prio = get_op_prio(arg->op.op); 150 return data + field->offset;
1164} 151}
1165 152
1166static enum event_type 153int trace_parse_common_type(void *data)
1167process_op(struct event *event, struct print_arg *arg, char **tok)
1168{ 154{
1169 struct print_arg *left, *right = NULL; 155 struct pevent_record record;
1170 enum event_type type;
1171 char *token;
1172
1173 /* the op is passed in via tok */
1174 token = *tok;
1175
1176 if (arg->type == PRINT_OP && !arg->op.left) {
1177 /* handle single op */
1178 if (token[1]) {
1179 die("bad op token %s", token);
1180 return EVENT_ERROR;
1181 }
1182 switch (token[0]) {
1183 case '!':
1184 case '+':
1185 case '-':
1186 break;
1187 default:
1188 die("bad op token %s", token);
1189 return EVENT_ERROR;
1190 }
1191
1192 /* make an empty left */
1193 left = malloc_or_die(sizeof(*left));
1194 left->type = PRINT_NULL;
1195 arg->op.left = left;
1196
1197 right = malloc_or_die(sizeof(*right));
1198 arg->op.right = right;
1199
1200 type = process_arg(event, right, tok);
1201
1202 } else if (strcmp(token, "?") == 0) {
1203
1204 left = malloc_or_die(sizeof(*left));
1205 /* copy the top arg to the left */
1206 *left = *arg;
1207
1208 arg->type = PRINT_OP;
1209 arg->op.op = token;
1210 arg->op.left = left;
1211 arg->op.prio = 0;
1212
1213 type = process_cond(event, arg, tok);
1214
1215 } else if (strcmp(token, ">>") == 0 ||
1216 strcmp(token, "<<") == 0 ||
1217 strcmp(token, "&") == 0 ||
1218 strcmp(token, "|") == 0 ||
1219 strcmp(token, "&&") == 0 ||
1220 strcmp(token, "||") == 0 ||
1221 strcmp(token, "-") == 0 ||
1222 strcmp(token, "+") == 0 ||
1223 strcmp(token, "*") == 0 ||
1224 strcmp(token, "^") == 0 ||
1225 strcmp(token, "/") == 0 ||
1226 strcmp(token, "<") == 0 ||
1227 strcmp(token, ">") == 0 ||
1228 strcmp(token, "==") == 0 ||
1229 strcmp(token, "!=") == 0) {
1230
1231 left = malloc_or_die(sizeof(*left));
1232
1233 /* copy the top arg to the left */
1234 *left = *arg;
1235
1236 arg->type = PRINT_OP;
1237 arg->op.op = token;
1238 arg->op.left = left;
1239
1240 set_op_prio(arg);
1241
1242 right = malloc_or_die(sizeof(*right));
1243
1244 type = read_token_item(&token);
1245 *tok = token;
1246
1247 /* could just be a type pointer */
1248 if ((strcmp(arg->op.op, "*") == 0) &&
1249 type == EVENT_DELIM && (strcmp(token, ")") == 0)) {
1250 if (left->type != PRINT_ATOM)
1251 die("bad pointer type");
1252 left->atom.atom = realloc(left->atom.atom,
1253 sizeof(left->atom.atom) + 3);
1254 strcat(left->atom.atom, " *");
1255 *arg = *left;
1256 free(arg);
1257
1258 return type;
1259 }
1260
1261 type = process_arg_token(event, right, tok, type);
1262
1263 arg->op.right = right;
1264
1265 } else if (strcmp(token, "[") == 0) {
1266
1267 left = malloc_or_die(sizeof(*left));
1268 *left = *arg;
1269
1270 arg->type = PRINT_OP;
1271 arg->op.op = token;
1272 arg->op.left = left;
1273
1274 arg->op.prio = 0;
1275 type = process_array(event, arg, tok);
1276
1277 } else {
1278 warning("unknown op '%s'", token);
1279 event->flags |= EVENT_FL_FAILED;
1280 /* the arg is now the left side */
1281 return EVENT_NONE;
1282 }
1283
1284 if (type == EVENT_OP) {
1285 int prio;
1286
1287 /* higher prios need to be closer to the root */
1288 prio = get_op_prio(*tok);
1289
1290 if (prio > arg->op.prio)
1291 return process_op(event, arg, tok);
1292 156
1293 return process_op(event, right, tok); 157 record.data = data;
1294 } 158 return pevent_data_type(pevent, &record);
1295
1296 return type;
1297} 159}
1298 160
1299static enum event_type 161int trace_parse_common_pid(void *data)
1300process_entry(struct event *event __unused, struct print_arg *arg,
1301 char **tok)
1302{ 162{
1303 enum event_type type; 163 struct pevent_record record;
1304 char *field;
1305 char *token;
1306
1307 if (read_expected(EVENT_OP, "->") < 0)
1308 return EVENT_ERROR;
1309
1310 if (read_expect_type(EVENT_ITEM, &token) < 0)
1311 goto fail;
1312 field = token;
1313
1314 arg->type = PRINT_FIELD;
1315 arg->field.name = field;
1316
1317 if (is_flag_field) {
1318 arg->field.field = find_any_field(event, arg->field.name);
1319 arg->field.field->flags |= FIELD_IS_FLAG;
1320 is_flag_field = 0;
1321 } else if (is_symbolic_field) {
1322 arg->field.field = find_any_field(event, arg->field.name);
1323 arg->field.field->flags |= FIELD_IS_SYMBOLIC;
1324 is_symbolic_field = 0;
1325 }
1326
1327 type = read_token(&token);
1328 *tok = token;
1329 164
1330 return type; 165 record.data = data;
1331 166 return pevent_data_pid(pevent, &record);
1332fail:
1333 free_token(token);
1334 return EVENT_ERROR;
1335} 167}
1336 168
1337static char *arg_eval (struct print_arg *arg); 169unsigned long long read_size(void *ptr, int size)
1338
1339static long long arg_num_eval(struct print_arg *arg)
1340{ 170{
1341 long long left, right; 171 return pevent_read_number(pevent, ptr, size);
1342 long long val = 0;
1343
1344 switch (arg->type) {
1345 case PRINT_ATOM:
1346 val = strtoll(arg->atom.atom, NULL, 0);
1347 break;
1348 case PRINT_TYPE:
1349 val = arg_num_eval(arg->typecast.item);
1350 break;
1351 case PRINT_OP:
1352 switch (arg->op.op[0]) {
1353 case '|':
1354 left = arg_num_eval(arg->op.left);
1355 right = arg_num_eval(arg->op.right);
1356 if (arg->op.op[1])
1357 val = left || right;
1358 else
1359 val = left | right;
1360 break;
1361 case '&':
1362 left = arg_num_eval(arg->op.left);
1363 right = arg_num_eval(arg->op.right);
1364 if (arg->op.op[1])
1365 val = left && right;
1366 else
1367 val = left & right;
1368 break;
1369 case '<':
1370 left = arg_num_eval(arg->op.left);
1371 right = arg_num_eval(arg->op.right);
1372 switch (arg->op.op[1]) {
1373 case 0:
1374 val = left < right;
1375 break;
1376 case '<':
1377 val = left << right;
1378 break;
1379 case '=':
1380 val = left <= right;
1381 break;
1382 default:
1383 die("unknown op '%s'", arg->op.op);
1384 }
1385 break;
1386 case '>':
1387 left = arg_num_eval(arg->op.left);
1388 right = arg_num_eval(arg->op.right);
1389 switch (arg->op.op[1]) {
1390 case 0:
1391 val = left > right;
1392 break;
1393 case '>':
1394 val = left >> right;
1395 break;
1396 case '=':
1397 val = left >= right;
1398 break;
1399 default:
1400 die("unknown op '%s'", arg->op.op);
1401 }
1402 break;
1403 case '=':
1404 left = arg_num_eval(arg->op.left);
1405 right = arg_num_eval(arg->op.right);
1406
1407 if (arg->op.op[1] != '=')
1408 die("unknown op '%s'", arg->op.op);
1409
1410 val = left == right;
1411 break;
1412 case '!':
1413 left = arg_num_eval(arg->op.left);
1414 right = arg_num_eval(arg->op.right);
1415
1416 switch (arg->op.op[1]) {
1417 case '=':
1418 val = left != right;
1419 break;
1420 default:
1421 die("unknown op '%s'", arg->op.op);
1422 }
1423 break;
1424 case '+':
1425 left = arg_num_eval(arg->op.left);
1426 right = arg_num_eval(arg->op.right);
1427 val = left + right;
1428 break;
1429 default:
1430 die("unknown op '%s'", arg->op.op);
1431 }
1432 break;
1433
1434 case PRINT_NULL:
1435 case PRINT_FIELD ... PRINT_SYMBOL:
1436 case PRINT_STRING:
1437 default:
1438 die("invalid eval type %d", arg->type);
1439
1440 }
1441 return val;
1442} 172}
1443 173
1444static char *arg_eval (struct print_arg *arg) 174struct event_format *trace_find_event(int type)
1445{ 175{
1446 long long val; 176 return pevent_find_event(pevent, type);
1447 static char buf[20];
1448
1449 switch (arg->type) {
1450 case PRINT_ATOM:
1451 return arg->atom.atom;
1452 case PRINT_TYPE:
1453 return arg_eval(arg->typecast.item);
1454 case PRINT_OP:
1455 val = arg_num_eval(arg);
1456 sprintf(buf, "%lld", val);
1457 return buf;
1458
1459 case PRINT_NULL:
1460 case PRINT_FIELD ... PRINT_SYMBOL:
1461 case PRINT_STRING:
1462 default:
1463 die("invalid eval type %d", arg->type);
1464 break;
1465 }
1466
1467 return NULL;
1468} 177}
1469 178
1470static enum event_type
1471process_fields(struct event *event, struct print_flag_sym **list, char **tok)
1472{
1473 enum event_type type;
1474 struct print_arg *arg = NULL;
1475 struct print_flag_sym *field;
1476 char *token = NULL;
1477 char *value;
1478
1479 do {
1480 free_token(token);
1481 type = read_token_item(&token);
1482 if (test_type_token(type, token, EVENT_OP, "{"))
1483 break;
1484
1485 arg = malloc_or_die(sizeof(*arg));
1486
1487 free_token(token);
1488 type = process_arg(event, arg, &token);
1489
1490 if (type == EVENT_OP)
1491 type = process_op(event, arg, &token);
1492
1493 if (type == EVENT_ERROR)
1494 goto out_free;
1495
1496 if (test_type_token(type, token, EVENT_DELIM, ","))
1497 goto out_free;
1498
1499 field = malloc_or_die(sizeof(*field));
1500 memset(field, 0, sizeof(*field));
1501
1502 value = arg_eval(arg);
1503 field->value = strdup(value);
1504
1505 free_token(token);
1506 type = process_arg(event, arg, &token);
1507 if (test_type_token(type, token, EVENT_OP, "}"))
1508 goto out_free;
1509
1510 value = arg_eval(arg);
1511 field->str = strdup(value);
1512 free_arg(arg);
1513 arg = NULL;
1514
1515 *list = field;
1516 list = &field->next;
1517 179
1518 free_token(token); 180void print_trace_event(int cpu, void *data, int size)
1519 type = read_token_item(&token);
1520 } while (type == EVENT_DELIM && strcmp(token, ",") == 0);
1521
1522 *tok = token;
1523 return type;
1524
1525out_free:
1526 free_arg(arg);
1527 free_token(token);
1528
1529 return EVENT_ERROR;
1530}
1531
1532static enum event_type
1533process_flags(struct event *event, struct print_arg *arg, char **tok)
1534{ 181{
1535 struct print_arg *field; 182 struct event_format *event;
1536 enum event_type type; 183 struct pevent_record record;
1537 char *token; 184 struct trace_seq s;
1538 185 int type;
1539 memset(arg, 0, sizeof(*arg));
1540 arg->type = PRINT_FLAGS;
1541
1542 if (read_expected_item(EVENT_DELIM, "(") < 0)
1543 return EVENT_ERROR;
1544
1545 field = malloc_or_die(sizeof(*field));
1546
1547 type = process_arg(event, field, &token);
1548 while (type == EVENT_OP)
1549 type = process_op(event, field, &token);
1550 if (test_type_token(type, token, EVENT_DELIM, ","))
1551 goto out_free;
1552 186
1553 arg->flags.field = field; 187 type = trace_parse_common_type(data);
1554 188
1555 type = read_token_item(&token); 189 event = trace_find_event(type);
1556 if (event_item_type(type)) { 190 if (!event) {
1557 arg->flags.delim = token; 191 warning("ug! no event found for type %d", type);
1558 type = read_token_item(&token); 192 return;
1559 } 193 }
1560 194
1561 if (test_type_token(type, token, EVENT_DELIM, ",")) 195 memset(&record, 0, sizeof(record));
1562 goto out_free; 196 record.cpu = cpu;
1563 197 record.size = size;
1564 type = process_fields(event, &arg->flags.flags, &token); 198 record.data = data;
1565 if (test_type_token(type, token, EVENT_DELIM, ")"))
1566 goto out_free;
1567 199
1568 free_token(token); 200 trace_seq_init(&s);
1569 type = read_token_item(tok); 201 pevent_print_event(pevent, &s, &record);
1570 return type; 202 trace_seq_do_printf(&s);
1571 203 printf("\n");
1572out_free:
1573 free_token(token);
1574 return EVENT_ERROR;
1575} 204}
1576 205
1577static enum event_type 206void print_event(int cpu, void *data, int size, unsigned long long nsecs,
1578process_symbols(struct event *event, struct print_arg *arg, char **tok) 207 char *comm)
1579{ 208{
1580 struct print_arg *field; 209 struct pevent_record record;
1581 enum event_type type; 210 struct trace_seq s;
1582 char *token; 211 int pid;
1583
1584 memset(arg, 0, sizeof(*arg));
1585 arg->type = PRINT_SYMBOL;
1586
1587 if (read_expected_item(EVENT_DELIM, "(") < 0)
1588 return EVENT_ERROR;
1589
1590 field = malloc_or_die(sizeof(*field));
1591
1592 type = process_arg(event, field, &token);
1593 if (test_type_token(type, token, EVENT_DELIM, ","))
1594 goto out_free;
1595 212
1596 arg->symbol.field = field; 213 pevent->latency_format = latency_format;
1597 214
1598 type = process_fields(event, &arg->symbol.symbols, &token); 215 record.ts = nsecs;
1599 if (test_type_token(type, token, EVENT_DELIM, ")")) 216 record.cpu = cpu;
1600 goto out_free; 217 record.size = size;
218 record.data = data;
219 pid = pevent_data_pid(pevent, &record);
1601 220
1602 free_token(token); 221 if (!pevent_pid_is_registered(pevent, pid))
1603 type = read_token_item(tok); 222 pevent_register_comm(pevent, comm, pid);
1604 return type;
1605 223
1606out_free: 224 trace_seq_init(&s);
1607 free_token(token); 225 pevent_print_event(pevent, &s, &record);
1608 return EVENT_ERROR; 226 trace_seq_do_printf(&s);
227 printf("\n");
1609} 228}
1610 229
1611static enum event_type 230void parse_proc_kallsyms(char *file, unsigned int size __unused)
1612process_paren(struct event *event, struct print_arg *arg, char **tok)
1613{ 231{
1614 struct print_arg *item_arg; 232 unsigned long long addr;
1615 enum event_type type; 233 char *func;
1616 char *token; 234 char *line;
1617 235 char *next = NULL;
1618 type = process_arg(event, arg, &token); 236 char *addr_str;
1619 237 char *mod;
1620 if (type == EVENT_ERROR) 238 char ch;
1621 return EVENT_ERROR;
1622
1623 if (type == EVENT_OP)
1624 type = process_op(event, arg, &token);
1625
1626 if (type == EVENT_ERROR)
1627 return EVENT_ERROR;
1628
1629 if (test_type_token(type, token, EVENT_DELIM, ")")) {
1630 free_token(token);
1631 return EVENT_ERROR;
1632 }
1633
1634 free_token(token);
1635 type = read_token_item(&token);
1636
1637 /*
1638 * If the next token is an item or another open paren, then
1639 * this was a typecast.
1640 */
1641 if (event_item_type(type) ||
1642 (type == EVENT_DELIM && strcmp(token, "(") == 0)) {
1643
1644 /* make this a typecast and contine */
1645 239
1646 /* prevous must be an atom */ 240 line = strtok_r(file, "\n", &next);
1647 if (arg->type != PRINT_ATOM) 241 while (line) {
1648 die("previous needed to be PRINT_ATOM"); 242 mod = NULL;
243 sscanf(line, "%as %c %as\t[%as",
244 (float *)(void *)&addr_str, /* workaround gcc warning */
245 &ch, (float *)(void *)&func, (float *)(void *)&mod);
246 addr = strtoull(addr_str, NULL, 16);
247 free(addr_str);
1649 248
1650 item_arg = malloc_or_die(sizeof(*item_arg)); 249 /* truncate the extra ']' */
250 if (mod)
251 mod[strlen(mod) - 1] = 0;
1651 252
1652 arg->type = PRINT_TYPE; 253 pevent_register_function(pevent, func, addr, mod);
1653 arg->typecast.type = arg->atom.atom; 254 free(func);
1654 arg->typecast.item = item_arg; 255 free(mod);
1655 type = process_arg_token(event, item_arg, &token, type);
1656 256
257 line = strtok_r(NULL, "\n", &next);
1657 } 258 }
1658
1659 *tok = token;
1660 return type;
1661} 259}
1662 260
1663 261void parse_ftrace_printk(char *file, unsigned int size __unused)
1664static enum event_type
1665process_str(struct event *event __unused, struct print_arg *arg, char **tok)
1666{ 262{
1667 enum event_type type; 263 unsigned long long addr;
1668 char *token; 264 char *printk;
1669 265 char *line;
1670 if (read_expected(EVENT_DELIM, "(") < 0) 266 char *next = NULL;
1671 return EVENT_ERROR; 267 char *addr_str;
1672 268 char *fmt;
1673 if (read_expect_type(EVENT_ITEM, &token) < 0)
1674 goto fail;
1675
1676 arg->type = PRINT_STRING;
1677 arg->string.string = token;
1678 arg->string.offset = -1;
1679
1680 if (read_expected(EVENT_DELIM, ")") < 0)
1681 return EVENT_ERROR;
1682
1683 type = read_token(&token);
1684 *tok = token;
1685
1686 return type;
1687fail:
1688 free_token(token);
1689 return EVENT_ERROR;
1690}
1691 269
1692enum event_type 270 line = strtok_r(file, "\n", &next);
1693process_arg_token(struct event *event, struct print_arg *arg, 271 while (line) {
1694 char **tok, enum event_type type) 272 addr_str = strtok_r(line, ":", &fmt);
1695{ 273 if (!addr_str) {
1696 char *token; 274 warning("printk format with empty entry");
1697 char *atom;
1698
1699 token = *tok;
1700
1701 switch (type) {
1702 case EVENT_ITEM:
1703 if (strcmp(token, "REC") == 0) {
1704 free_token(token);
1705 type = process_entry(event, arg, &token);
1706 } else if (strcmp(token, "__print_flags") == 0) {
1707 free_token(token);
1708 is_flag_field = 1;
1709 type = process_flags(event, arg, &token);
1710 } else if (strcmp(token, "__print_symbolic") == 0) {
1711 free_token(token);
1712 is_symbolic_field = 1;
1713 type = process_symbols(event, arg, &token);
1714 } else if (strcmp(token, "__get_str") == 0) {
1715 free_token(token);
1716 type = process_str(event, arg, &token);
1717 } else {
1718 atom = token;
1719 /* test the next token */
1720 type = read_token_item(&token);
1721
1722 /* atoms can be more than one token long */
1723 while (type == EVENT_ITEM) {
1724 atom = realloc(atom, strlen(atom) + strlen(token) + 2);
1725 strcat(atom, " ");
1726 strcat(atom, token);
1727 free_token(token);
1728 type = read_token_item(&token);
1729 }
1730
1731 /* todo, test for function */
1732
1733 arg->type = PRINT_ATOM;
1734 arg->atom.atom = atom;
1735 }
1736 break;
1737 case EVENT_DQUOTE:
1738 case EVENT_SQUOTE:
1739 arg->type = PRINT_ATOM;
1740 arg->atom.atom = token;
1741 type = read_token_item(&token);
1742 break;
1743 case EVENT_DELIM:
1744 if (strcmp(token, "(") == 0) {
1745 free_token(token);
1746 type = process_paren(event, arg, &token);
1747 break; 275 break;
1748 } 276 }
1749 case EVENT_OP: 277 addr = strtoull(addr_str, NULL, 16);
1750 /* handle single ops */ 278 /* fmt still has a space, skip it */
1751 arg->type = PRINT_OP; 279 printk = strdup(fmt+1);
1752 arg->op.op = token; 280 line = strtok_r(NULL, "\n", &next);
1753 arg->op.left = NULL; 281 pevent_register_print_string(pevent, printk, addr);
1754 type = process_op(event, arg, &token);
1755
1756 break;
1757
1758 case EVENT_ERROR ... EVENT_NEWLINE:
1759 default:
1760 die("unexpected type %d", type);
1761 }
1762 *tok = token;
1763
1764 return type;
1765}
1766
1767static int event_read_print_args(struct event *event, struct print_arg **list)
1768{
1769 enum event_type type = EVENT_ERROR;
1770 struct print_arg *arg;
1771 char *token;
1772 int args = 0;
1773
1774 do {
1775 if (type == EVENT_NEWLINE) {
1776 free_token(token);
1777 type = read_token_item(&token);
1778 continue;
1779 }
1780
1781 arg = malloc_or_die(sizeof(*arg));
1782 memset(arg, 0, sizeof(*arg));
1783
1784 type = process_arg(event, arg, &token);
1785
1786 if (type == EVENT_ERROR) {
1787 free_arg(arg);
1788 return -1;
1789 }
1790
1791 *list = arg;
1792 args++;
1793
1794 if (type == EVENT_OP) {
1795 type = process_op(event, arg, &token);
1796 list = &arg->next;
1797 continue;
1798 }
1799
1800 if (type == EVENT_DELIM && strcmp(token, ",") == 0) {
1801 free_token(token);
1802 *list = arg;
1803 list = &arg->next;
1804 continue;
1805 }
1806 break;
1807 } while (type != EVENT_NONE);
1808
1809 if (type != EVENT_NONE)
1810 free_token(token);
1811
1812 return args;
1813}
1814
1815static int event_read_print(struct event *event)
1816{
1817 enum event_type type;
1818 char *token;
1819 int ret;
1820
1821 if (read_expected_item(EVENT_ITEM, "print") < 0)
1822 return -1;
1823
1824 if (read_expected(EVENT_ITEM, "fmt") < 0)
1825 return -1;
1826
1827 if (read_expected(EVENT_OP, ":") < 0)
1828 return -1;
1829
1830 if (read_expect_type(EVENT_DQUOTE, &token) < 0)
1831 goto fail;
1832
1833 concat:
1834 event->print_fmt.format = token;
1835 event->print_fmt.args = NULL;
1836
1837 /* ok to have no arg */
1838 type = read_token_item(&token);
1839
1840 if (type == EVENT_NONE)
1841 return 0;
1842
1843 /* Handle concatination of print lines */
1844 if (type == EVENT_DQUOTE) {
1845 char *cat;
1846
1847 cat = malloc_or_die(strlen(event->print_fmt.format) +
1848 strlen(token) + 1);
1849 strcpy(cat, event->print_fmt.format);
1850 strcat(cat, token);
1851 free_token(token);
1852 free_token(event->print_fmt.format);
1853 event->print_fmt.format = NULL;
1854 token = cat;
1855 goto concat;
1856 }
1857
1858 if (test_type_token(type, token, EVENT_DELIM, ","))
1859 goto fail;
1860
1861 free_token(token);
1862
1863 ret = event_read_print_args(event, &event->print_fmt.args);
1864 if (ret < 0)
1865 return -1;
1866
1867 return ret;
1868
1869 fail:
1870 free_token(token);
1871 return -1;
1872}
1873
1874static struct format_field *
1875find_common_field(struct event *event, const char *name)
1876{
1877 struct format_field *format;
1878
1879 for (format = event->format.common_fields;
1880 format; format = format->next) {
1881 if (strcmp(format->name, name) == 0)
1882 break;
1883 }
1884
1885 return format;
1886}
1887
1888static struct format_field *
1889find_field(struct event *event, const char *name)
1890{
1891 struct format_field *format;
1892
1893 for (format = event->format.fields;
1894 format; format = format->next) {
1895 if (strcmp(format->name, name) == 0)
1896 break;
1897 } 282 }
1898
1899 return format;
1900} 283}
1901 284
1902static struct format_field * 285int parse_ftrace_file(char *buf, unsigned long size)
1903find_any_field(struct event *event, const char *name)
1904{ 286{
1905 struct format_field *format; 287 return pevent_parse_event(pevent, buf, size, "ftrace");
1906
1907 format = find_common_field(event, name);
1908 if (format)
1909 return format;
1910 return find_field(event, name);
1911} 288}
1912 289
1913unsigned long long read_size(void *ptr, int size) 290int parse_event_file(char *buf, unsigned long size, char *sys)
1914{ 291{
1915 switch (size) { 292 return pevent_parse_event(pevent, buf, size, sys);
1916 case 1:
1917 return *(unsigned char *)ptr;
1918 case 2:
1919 return data2host2(ptr);
1920 case 4:
1921 return data2host4(ptr);
1922 case 8:
1923 return data2host8(ptr);
1924 default:
1925 /* BUG! */
1926 return 0;
1927 }
1928} 293}
1929 294
1930unsigned long long 295struct event_format *trace_find_next_event(struct event_format *event)
1931raw_field_value(struct event *event, const char *name, void *data)
1932{ 296{
1933 struct format_field *field; 297 static int idx;
1934
1935 field = find_any_field(event, name);
1936 if (!field)
1937 return 0ULL;
1938 298
1939 return read_size(data + field->offset, field->size); 299 if (!pevent->events)
1940}
1941
1942void *raw_field_ptr(struct event *event, const char *name, void *data)
1943{
1944 struct format_field *field;
1945
1946 field = find_any_field(event, name);
1947 if (!field)
1948 return NULL; 300 return NULL;
1949 301
1950 if (field->flags & FIELD_IS_DYNAMIC) { 302 if (!event) {
1951 int offset; 303 idx = 0;
1952 304 return pevent->events[0];
1953 offset = *(int *)(data + field->offset);
1954 offset &= 0xffff;
1955
1956 return data + offset;
1957 }
1958
1959 return data + field->offset;
1960}
1961
1962static int get_common_info(const char *type, int *offset, int *size)
1963{
1964 struct event *event;
1965 struct format_field *field;
1966
1967 /*
1968 * All events should have the same common elements.
1969 * Pick any event to find where the type is;
1970 */
1971 if (!event_list)
1972 die("no event_list!");
1973
1974 event = event_list;
1975 field = find_common_field(event, type);
1976 if (!field)
1977 die("field '%s' not found", type);
1978
1979 *offset = field->offset;
1980 *size = field->size;
1981
1982 return 0;
1983}
1984
1985static int __parse_common(void *data, int *size, int *offset,
1986 const char *name)
1987{
1988 int ret;
1989
1990 if (!*size) {
1991 ret = get_common_info(name, offset, size);
1992 if (ret < 0)
1993 return ret;
1994 } 305 }
1995 return read_size(data + *offset, *size);
1996}
1997
1998int trace_parse_common_type(void *data)
1999{
2000 static int type_offset;
2001 static int type_size;
2002
2003 return __parse_common(data, &type_size, &type_offset,
2004 "common_type");
2005}
2006
2007int trace_parse_common_pid(void *data)
2008{
2009 static int pid_offset;
2010 static int pid_size;
2011
2012 return __parse_common(data, &pid_size, &pid_offset,
2013 "common_pid");
2014}
2015
2016int parse_common_pc(void *data)
2017{
2018 static int pc_offset;
2019 static int pc_size;
2020
2021 return __parse_common(data, &pc_size, &pc_offset,
2022 "common_preempt_count");
2023}
2024
2025int parse_common_flags(void *data)
2026{
2027 static int flags_offset;
2028 static int flags_size;
2029
2030 return __parse_common(data, &flags_size, &flags_offset,
2031 "common_flags");
2032}
2033
2034int parse_common_lock_depth(void *data)
2035{
2036 static int ld_offset;
2037 static int ld_size;
2038 int ret;
2039 306
2040 ret = __parse_common(data, &ld_size, &ld_offset, 307 if (idx < pevent->nr_events && event == pevent->events[idx]) {
2041 "common_lock_depth"); 308 idx++;
2042 if (ret < 0) 309 if (idx == pevent->nr_events)
2043 return -1; 310 return NULL;
2044 311 return pevent->events[idx];
2045 return ret;
2046}
2047
2048struct event *trace_find_event(int id)
2049{
2050 struct event *event;
2051
2052 for (event = event_list; event; event = event->next) {
2053 if (event->id == id)
2054 break;
2055 } 312 }
2056 return event;
2057}
2058
2059struct event *trace_find_next_event(struct event *event)
2060{
2061 if (!event)
2062 return event_list;
2063
2064 return event->next;
2065}
2066
2067static unsigned long long eval_num_arg(void *data, int size,
2068 struct event *event, struct print_arg *arg)
2069{
2070 unsigned long long val = 0;
2071 unsigned long long left, right;
2072 struct print_arg *larg;
2073 313
2074 switch (arg->type) { 314 for (idx = 1; idx < pevent->nr_events; idx++) {
2075 case PRINT_NULL: 315 if (event == pevent->events[idx - 1])
2076 /* ?? */ 316 return pevent->events[idx];
2077 return 0;
2078 case PRINT_ATOM:
2079 return strtoull(arg->atom.atom, NULL, 0);
2080 case PRINT_FIELD:
2081 if (!arg->field.field) {
2082 arg->field.field = find_any_field(event, arg->field.name);
2083 if (!arg->field.field)
2084 die("field %s not found", arg->field.name);
2085 }
2086 /* must be a number */
2087 val = read_size(data + arg->field.field->offset,
2088 arg->field.field->size);
2089 break;
2090 case PRINT_FLAGS:
2091 case PRINT_SYMBOL:
2092 break;
2093 case PRINT_TYPE:
2094 return eval_num_arg(data, size, event, arg->typecast.item);
2095 case PRINT_STRING:
2096 return 0;
2097 break;
2098 case PRINT_OP:
2099 if (strcmp(arg->op.op, "[") == 0) {
2100 /*
2101 * Arrays are special, since we don't want
2102 * to read the arg as is.
2103 */
2104 if (arg->op.left->type != PRINT_FIELD)
2105 goto default_op; /* oops, all bets off */
2106 larg = arg->op.left;
2107 if (!larg->field.field) {
2108 larg->field.field =
2109 find_any_field(event, larg->field.name);
2110 if (!larg->field.field)
2111 die("field %s not found", larg->field.name);
2112 }
2113 right = eval_num_arg(data, size, event, arg->op.right);
2114 val = read_size(data + larg->field.field->offset +
2115 right * long_size, long_size);
2116 break;
2117 }
2118 default_op:
2119 left = eval_num_arg(data, size, event, arg->op.left);
2120 right = eval_num_arg(data, size, event, arg->op.right);
2121 switch (arg->op.op[0]) {
2122 case '|':
2123 if (arg->op.op[1])
2124 val = left || right;
2125 else
2126 val = left | right;
2127 break;
2128 case '&':
2129 if (arg->op.op[1])
2130 val = left && right;
2131 else
2132 val = left & right;
2133 break;
2134 case '<':
2135 switch (arg->op.op[1]) {
2136 case 0:
2137 val = left < right;
2138 break;
2139 case '<':
2140 val = left << right;
2141 break;
2142 case '=':
2143 val = left <= right;
2144 break;
2145 default:
2146 die("unknown op '%s'", arg->op.op);
2147 }
2148 break;
2149 case '>':
2150 switch (arg->op.op[1]) {
2151 case 0:
2152 val = left > right;
2153 break;
2154 case '>':
2155 val = left >> right;
2156 break;
2157 case '=':
2158 val = left >= right;
2159 break;
2160 default:
2161 die("unknown op '%s'", arg->op.op);
2162 }
2163 break;
2164 case '=':
2165 if (arg->op.op[1] != '=')
2166 die("unknown op '%s'", arg->op.op);
2167 val = left == right;
2168 break;
2169 case '-':
2170 val = left - right;
2171 break;
2172 case '+':
2173 val = left + right;
2174 break;
2175 default:
2176 die("unknown op '%s'", arg->op.op);
2177 }
2178 break;
2179 default: /* not sure what to do there */
2180 return 0;
2181 } 317 }
2182 return val; 318 return NULL;
2183} 319}
2184 320
2185struct flag { 321struct flag {
@@ -2221,933 +357,3 @@ unsigned long long eval_flag(const char *flag)
2221 357
2222 return 0; 358 return 0;
2223} 359}
2224
2225static void print_str_arg(void *data, int size,
2226 struct event *event, struct print_arg *arg)
2227{
2228 struct print_flag_sym *flag;
2229 unsigned long long val, fval;
2230 char *str;
2231 int print;
2232
2233 switch (arg->type) {
2234 case PRINT_NULL:
2235 /* ?? */
2236 return;
2237 case PRINT_ATOM:
2238 printf("%s", arg->atom.atom);
2239 return;
2240 case PRINT_FIELD:
2241 if (!arg->field.field) {
2242 arg->field.field = find_any_field(event, arg->field.name);
2243 if (!arg->field.field)
2244 die("field %s not found", arg->field.name);
2245 }
2246 str = malloc_or_die(arg->field.field->size + 1);
2247 memcpy(str, data + arg->field.field->offset,
2248 arg->field.field->size);
2249 str[arg->field.field->size] = 0;
2250 printf("%s", str);
2251 free(str);
2252 break;
2253 case PRINT_FLAGS:
2254 val = eval_num_arg(data, size, event, arg->flags.field);
2255 print = 0;
2256 for (flag = arg->flags.flags; flag; flag = flag->next) {
2257 fval = eval_flag(flag->value);
2258 if (!val && !fval) {
2259 printf("%s", flag->str);
2260 break;
2261 }
2262 if (fval && (val & fval) == fval) {
2263 if (print && arg->flags.delim)
2264 printf("%s", arg->flags.delim);
2265 printf("%s", flag->str);
2266 print = 1;
2267 val &= ~fval;
2268 }
2269 }
2270 break;
2271 case PRINT_SYMBOL:
2272 val = eval_num_arg(data, size, event, arg->symbol.field);
2273 for (flag = arg->symbol.symbols; flag; flag = flag->next) {
2274 fval = eval_flag(flag->value);
2275 if (val == fval) {
2276 printf("%s", flag->str);
2277 break;
2278 }
2279 }
2280 break;
2281
2282 case PRINT_TYPE:
2283 break;
2284 case PRINT_STRING: {
2285 int str_offset;
2286
2287 if (arg->string.offset == -1) {
2288 struct format_field *f;
2289
2290 f = find_any_field(event, arg->string.string);
2291 arg->string.offset = f->offset;
2292 }
2293 str_offset = *(int *)(data + arg->string.offset);
2294 str_offset &= 0xffff;
2295 printf("%s", ((char *)data) + str_offset);
2296 break;
2297 }
2298 case PRINT_OP:
2299 /*
2300 * The only op for string should be ? :
2301 */
2302 if (arg->op.op[0] != '?')
2303 return;
2304 val = eval_num_arg(data, size, event, arg->op.left);
2305 if (val)
2306 print_str_arg(data, size, event, arg->op.right->op.left);
2307 else
2308 print_str_arg(data, size, event, arg->op.right->op.right);
2309 break;
2310 default:
2311 /* well... */
2312 break;
2313 }
2314}
2315
2316static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event)
2317{
2318 static struct format_field *field, *ip_field;
2319 struct print_arg *args, *arg, **next;
2320 unsigned long long ip, val;
2321 char *ptr;
2322 void *bptr;
2323
2324 if (!field) {
2325 field = find_field(event, "buf");
2326 if (!field)
2327 die("can't find buffer field for binary printk");
2328 ip_field = find_field(event, "ip");
2329 if (!ip_field)
2330 die("can't find ip field for binary printk");
2331 }
2332
2333 ip = read_size(data + ip_field->offset, ip_field->size);
2334
2335 /*
2336 * The first arg is the IP pointer.
2337 */
2338 args = malloc_or_die(sizeof(*args));
2339 arg = args;
2340 arg->next = NULL;
2341 next = &arg->next;
2342
2343 arg->type = PRINT_ATOM;
2344 arg->atom.atom = malloc_or_die(32);
2345 sprintf(arg->atom.atom, "%lld", ip);
2346
2347 /* skip the first "%pf : " */
2348 for (ptr = fmt + 6, bptr = data + field->offset;
2349 bptr < data + size && *ptr; ptr++) {
2350 int ls = 0;
2351
2352 if (*ptr == '%') {
2353 process_again:
2354 ptr++;
2355 switch (*ptr) {
2356 case '%':
2357 break;
2358 case 'l':
2359 ls++;
2360 goto process_again;
2361 case 'L':
2362 ls = 2;
2363 goto process_again;
2364 case '0' ... '9':
2365 goto process_again;
2366 case 'p':
2367 ls = 1;
2368 /* fall through */
2369 case 'd':
2370 case 'u':
2371 case 'x':
2372 case 'i':
2373 /* the pointers are always 4 bytes aligned */
2374 bptr = (void *)(((unsigned long)bptr + 3) &
2375 ~3);
2376 switch (ls) {
2377 case 0:
2378 case 1:
2379 ls = long_size;
2380 break;
2381 case 2:
2382 ls = 8;
2383 default:
2384 break;
2385 }
2386 val = read_size(bptr, ls);
2387 bptr += ls;
2388 arg = malloc_or_die(sizeof(*arg));
2389 arg->next = NULL;
2390 arg->type = PRINT_ATOM;
2391 arg->atom.atom = malloc_or_die(32);
2392 sprintf(arg->atom.atom, "%lld", val);
2393 *next = arg;
2394 next = &arg->next;
2395 break;
2396 case 's':
2397 arg = malloc_or_die(sizeof(*arg));
2398 arg->next = NULL;
2399 arg->type = PRINT_STRING;
2400 arg->string.string = strdup(bptr);
2401 bptr += strlen(bptr) + 1;
2402 *next = arg;
2403 next = &arg->next;
2404 default:
2405 break;
2406 }
2407 }
2408 }
2409
2410 return args;
2411}
2412
2413static void free_args(struct print_arg *args)
2414{
2415 struct print_arg *next;
2416
2417 while (args) {
2418 next = args->next;
2419
2420 if (args->type == PRINT_ATOM)
2421 free(args->atom.atom);
2422 else
2423 free(args->string.string);
2424 free(args);
2425 args = next;
2426 }
2427}
2428
2429static char *get_bprint_format(void *data, int size __unused, struct event *event)
2430{
2431 unsigned long long addr;
2432 static struct format_field *field;
2433 struct printk_map *printk;
2434 char *format;
2435 char *p;
2436
2437 if (!field) {
2438 field = find_field(event, "fmt");
2439 if (!field)
2440 die("can't find format field for binary printk");
2441 printf("field->offset = %d size=%d\n", field->offset, field->size);
2442 }
2443
2444 addr = read_size(data + field->offset, field->size);
2445
2446 printk = find_printk(addr);
2447 if (!printk) {
2448 format = malloc_or_die(45);
2449 sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n",
2450 addr);
2451 return format;
2452 }
2453
2454 p = printk->printk;
2455 /* Remove any quotes. */
2456 if (*p == '"')
2457 p++;
2458 format = malloc_or_die(strlen(p) + 10);
2459 sprintf(format, "%s : %s", "%pf", p);
2460 /* remove ending quotes and new line since we will add one too */
2461 p = format + strlen(format) - 1;
2462 if (*p == '"')
2463 *p = 0;
2464
2465 p -= 2;
2466 if (strcmp(p, "\\n") == 0)
2467 *p = 0;
2468
2469 return format;
2470}
2471
2472static void pretty_print(void *data, int size, struct event *event)
2473{
2474 struct print_fmt *print_fmt = &event->print_fmt;
2475 struct print_arg *arg = print_fmt->args;
2476 struct print_arg *args = NULL;
2477 const char *ptr = print_fmt->format;
2478 unsigned long long val;
2479 struct func_map *func;
2480 const char *saveptr;
2481 char *bprint_fmt = NULL;
2482 char format[32];
2483 int show_func;
2484 int len;
2485 int ls;
2486
2487 if (event->flags & EVENT_FL_ISFUNC)
2488 ptr = " %pF <-- %pF";
2489
2490 if (event->flags & EVENT_FL_ISBPRINT) {
2491 bprint_fmt = get_bprint_format(data, size, event);
2492 args = make_bprint_args(bprint_fmt, data, size, event);
2493 arg = args;
2494 ptr = bprint_fmt;
2495 }
2496
2497 for (; *ptr; ptr++) {
2498 ls = 0;
2499 if (*ptr == '\\') {
2500 ptr++;
2501 switch (*ptr) {
2502 case 'n':
2503 printf("\n");
2504 break;
2505 case 't':
2506 printf("\t");
2507 break;
2508 case 'r':
2509 printf("\r");
2510 break;
2511 case '\\':
2512 printf("\\");
2513 break;
2514 default:
2515 printf("%c", *ptr);
2516 break;
2517 }
2518
2519 } else if (*ptr == '%') {
2520 saveptr = ptr;
2521 show_func = 0;
2522 cont_process:
2523 ptr++;
2524 switch (*ptr) {
2525 case '%':
2526 printf("%%");
2527 break;
2528 case 'l':
2529 ls++;
2530 goto cont_process;
2531 case 'L':
2532 ls = 2;
2533 goto cont_process;
2534 case 'z':
2535 case 'Z':
2536 case '0' ... '9':
2537 goto cont_process;
2538 case 'p':
2539 if (long_size == 4)
2540 ls = 1;
2541 else
2542 ls = 2;
2543
2544 if (*(ptr+1) == 'F' ||
2545 *(ptr+1) == 'f') {
2546 ptr++;
2547 show_func = *ptr;
2548 }
2549
2550 /* fall through */
2551 case 'd':
2552 case 'i':
2553 case 'x':
2554 case 'X':
2555 case 'u':
2556 if (!arg)
2557 die("no argument match");
2558
2559 len = ((unsigned long)ptr + 1) -
2560 (unsigned long)saveptr;
2561
2562 /* should never happen */
2563 if (len > 32)
2564 die("bad format!");
2565
2566 memcpy(format, saveptr, len);
2567 format[len] = 0;
2568
2569 val = eval_num_arg(data, size, event, arg);
2570 arg = arg->next;
2571
2572 if (show_func) {
2573 func = find_func(val);
2574 if (func) {
2575 printf("%s", func->func);
2576 if (show_func == 'F')
2577 printf("+0x%llx",
2578 val - func->addr);
2579 break;
2580 }
2581 }
2582 switch (ls) {
2583 case 0:
2584 printf(format, (int)val);
2585 break;
2586 case 1:
2587 printf(format, (long)val);
2588 break;
2589 case 2:
2590 printf(format, (long long)val);
2591 break;
2592 default:
2593 die("bad count (%d)", ls);
2594 }
2595 break;
2596 case 's':
2597 if (!arg)
2598 die("no matching argument");
2599
2600 print_str_arg(data, size, event, arg);
2601 arg = arg->next;
2602 break;
2603 default:
2604 printf(">%c<", *ptr);
2605
2606 }
2607 } else
2608 printf("%c", *ptr);
2609 }
2610
2611 if (args) {
2612 free_args(args);
2613 free(bprint_fmt);
2614 }
2615}
2616
2617static inline int log10_cpu(int nb)
2618{
2619 if (nb / 100)
2620 return 3;
2621 if (nb / 10)
2622 return 2;
2623 return 1;
2624}
2625
2626static void print_lat_fmt(void *data, int size __unused)
2627{
2628 unsigned int lat_flags;
2629 unsigned int pc;
2630 int lock_depth;
2631 int hardirq;
2632 int softirq;
2633
2634 lat_flags = parse_common_flags(data);
2635 pc = parse_common_pc(data);
2636 lock_depth = parse_common_lock_depth(data);
2637
2638 hardirq = lat_flags & TRACE_FLAG_HARDIRQ;
2639 softirq = lat_flags & TRACE_FLAG_SOFTIRQ;
2640
2641 printf("%c%c%c",
2642 (lat_flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
2643 (lat_flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
2644 'X' : '.',
2645 (lat_flags & TRACE_FLAG_NEED_RESCHED) ?
2646 'N' : '.',
2647 (hardirq && softirq) ? 'H' :
2648 hardirq ? 'h' : softirq ? 's' : '.');
2649
2650 if (pc)
2651 printf("%x", pc);
2652 else
2653 printf(".");
2654
2655 if (lock_depth < 0)
2656 printf(". ");
2657 else
2658 printf("%d ", lock_depth);
2659}
2660
2661#define TRACE_GRAPH_INDENT 2
2662
2663static struct record *
2664get_return_for_leaf(int cpu, int cur_pid, unsigned long long cur_func,
2665 struct record *next)
2666{
2667 struct format_field *field;
2668 struct event *event;
2669 unsigned long val;
2670 int type;
2671 int pid;
2672
2673 type = trace_parse_common_type(next->data);
2674 event = trace_find_event(type);
2675 if (!event)
2676 return NULL;
2677
2678 if (!(event->flags & EVENT_FL_ISFUNCRET))
2679 return NULL;
2680
2681 pid = trace_parse_common_pid(next->data);
2682 field = find_field(event, "func");
2683 if (!field)
2684 die("function return does not have field func");
2685
2686 val = read_size(next->data + field->offset, field->size);
2687
2688 if (cur_pid != pid || cur_func != val)
2689 return NULL;
2690
2691 /* this is a leaf, now advance the iterator */
2692 return trace_read_data(cpu);
2693}
2694
2695/* Signal a overhead of time execution to the output */
2696static void print_graph_overhead(unsigned long long duration)
2697{
2698 /* Non nested entry or return */
2699 if (duration == ~0ULL)
2700 return (void)printf(" ");
2701
2702 /* Duration exceeded 100 msecs */
2703 if (duration > 100000ULL)
2704 return (void)printf("! ");
2705
2706 /* Duration exceeded 10 msecs */
2707 if (duration > 10000ULL)
2708 return (void)printf("+ ");
2709
2710 printf(" ");
2711}
2712
2713static void print_graph_duration(unsigned long long duration)
2714{
2715 unsigned long usecs = duration / 1000;
2716 unsigned long nsecs_rem = duration % 1000;
2717 /* log10(ULONG_MAX) + '\0' */
2718 char msecs_str[21];
2719 char nsecs_str[5];
2720 int len;
2721 int i;
2722
2723 sprintf(msecs_str, "%lu", usecs);
2724
2725 /* Print msecs */
2726 len = printf("%lu", usecs);
2727
2728 /* Print nsecs (we don't want to exceed 7 numbers) */
2729 if (len < 7) {
2730 snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
2731 len += printf(".%s", nsecs_str);
2732 }
2733
2734 printf(" us ");
2735
2736 /* Print remaining spaces to fit the row's width */
2737 for (i = len; i < 7; i++)
2738 printf(" ");
2739
2740 printf("| ");
2741}
2742
2743static void
2744print_graph_entry_leaf(struct event *event, void *data, struct record *ret_rec)
2745{
2746 unsigned long long rettime, calltime;
2747 unsigned long long duration, depth;
2748 unsigned long long val;
2749 struct format_field *field;
2750 struct func_map *func;
2751 struct event *ret_event;
2752 int type;
2753 int i;
2754
2755 type = trace_parse_common_type(ret_rec->data);
2756 ret_event = trace_find_event(type);
2757
2758 field = find_field(ret_event, "rettime");
2759 if (!field)
2760 die("can't find rettime in return graph");
2761 rettime = read_size(ret_rec->data + field->offset, field->size);
2762
2763 field = find_field(ret_event, "calltime");
2764 if (!field)
2765 die("can't find rettime in return graph");
2766 calltime = read_size(ret_rec->data + field->offset, field->size);
2767
2768 duration = rettime - calltime;
2769
2770 /* Overhead */
2771 print_graph_overhead(duration);
2772
2773 /* Duration */
2774 print_graph_duration(duration);
2775
2776 field = find_field(event, "depth");
2777 if (!field)
2778 die("can't find depth in entry graph");
2779 depth = read_size(data + field->offset, field->size);
2780
2781 /* Function */
2782 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2783 printf(" ");
2784
2785 field = find_field(event, "func");
2786 if (!field)
2787 die("can't find func in entry graph");
2788 val = read_size(data + field->offset, field->size);
2789 func = find_func(val);
2790
2791 if (func)
2792 printf("%s();", func->func);
2793 else
2794 printf("%llx();", val);
2795}
2796
2797static void print_graph_nested(struct event *event, void *data)
2798{
2799 struct format_field *field;
2800 unsigned long long depth;
2801 unsigned long long val;
2802 struct func_map *func;
2803 int i;
2804
2805 /* No overhead */
2806 print_graph_overhead(-1);
2807
2808 /* No time */
2809 printf(" | ");
2810
2811 field = find_field(event, "depth");
2812 if (!field)
2813 die("can't find depth in entry graph");
2814 depth = read_size(data + field->offset, field->size);
2815
2816 /* Function */
2817 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2818 printf(" ");
2819
2820 field = find_field(event, "func");
2821 if (!field)
2822 die("can't find func in entry graph");
2823 val = read_size(data + field->offset, field->size);
2824 func = find_func(val);
2825
2826 if (func)
2827 printf("%s() {", func->func);
2828 else
2829 printf("%llx() {", val);
2830}
2831
2832static void
2833pretty_print_func_ent(void *data, int size, struct event *event,
2834 int cpu, int pid)
2835{
2836 struct format_field *field;
2837 struct record *rec;
2838 void *copy_data;
2839 unsigned long val;
2840
2841 if (latency_format) {
2842 print_lat_fmt(data, size);
2843 printf(" | ");
2844 }
2845
2846 field = find_field(event, "func");
2847 if (!field)
2848 die("function entry does not have func field");
2849
2850 val = read_size(data + field->offset, field->size);
2851
2852 /*
2853 * peek_data may unmap the data pointer. Copy it first.
2854 */
2855 copy_data = malloc_or_die(size);
2856 memcpy(copy_data, data, size);
2857 data = copy_data;
2858
2859 rec = trace_peek_data(cpu);
2860 if (rec) {
2861 rec = get_return_for_leaf(cpu, pid, val, rec);
2862 if (rec) {
2863 print_graph_entry_leaf(event, data, rec);
2864 goto out_free;
2865 }
2866 }
2867 print_graph_nested(event, data);
2868out_free:
2869 free(data);
2870}
2871
2872static void
2873pretty_print_func_ret(void *data, int size __unused, struct event *event)
2874{
2875 unsigned long long rettime, calltime;
2876 unsigned long long duration, depth;
2877 struct format_field *field;
2878 int i;
2879
2880 if (latency_format) {
2881 print_lat_fmt(data, size);
2882 printf(" | ");
2883 }
2884
2885 field = find_field(event, "rettime");
2886 if (!field)
2887 die("can't find rettime in return graph");
2888 rettime = read_size(data + field->offset, field->size);
2889
2890 field = find_field(event, "calltime");
2891 if (!field)
2892 die("can't find calltime in return graph");
2893 calltime = read_size(data + field->offset, field->size);
2894
2895 duration = rettime - calltime;
2896
2897 /* Overhead */
2898 print_graph_overhead(duration);
2899
2900 /* Duration */
2901 print_graph_duration(duration);
2902
2903 field = find_field(event, "depth");
2904 if (!field)
2905 die("can't find depth in entry graph");
2906 depth = read_size(data + field->offset, field->size);
2907
2908 /* Function */
2909 for (i = 0; i < (int)(depth * TRACE_GRAPH_INDENT); i++)
2910 printf(" ");
2911
2912 printf("}");
2913}
2914
2915static void
2916pretty_print_func_graph(void *data, int size, struct event *event,
2917 int cpu, int pid)
2918{
2919 if (event->flags & EVENT_FL_ISFUNCENT)
2920 pretty_print_func_ent(data, size, event, cpu, pid);
2921 else if (event->flags & EVENT_FL_ISFUNCRET)
2922 pretty_print_func_ret(data, size, event);
2923 printf("\n");
2924}
2925
2926void print_trace_event(int cpu, void *data, int size)
2927{
2928 struct event *event;
2929 int type;
2930 int pid;
2931
2932 type = trace_parse_common_type(data);
2933
2934 event = trace_find_event(type);
2935 if (!event) {
2936 warning("ug! no event found for type %d", type);
2937 return;
2938 }
2939
2940 pid = trace_parse_common_pid(data);
2941
2942 if (event->flags & (EVENT_FL_ISFUNCENT | EVENT_FL_ISFUNCRET))
2943 return pretty_print_func_graph(data, size, event, cpu, pid);
2944
2945 if (latency_format)
2946 print_lat_fmt(data, size);
2947
2948 if (event->flags & EVENT_FL_FAILED) {
2949 printf("EVENT '%s' FAILED TO PARSE\n",
2950 event->name);
2951 return;
2952 }
2953
2954 pretty_print(data, size, event);
2955}
2956
2957static void print_fields(struct print_flag_sym *field)
2958{
2959 printf("{ %s, %s }", field->value, field->str);
2960 if (field->next) {
2961 printf(", ");
2962 print_fields(field->next);
2963 }
2964}
2965
2966static void print_args(struct print_arg *args)
2967{
2968 int print_paren = 1;
2969
2970 switch (args->type) {
2971 case PRINT_NULL:
2972 printf("null");
2973 break;
2974 case PRINT_ATOM:
2975 printf("%s", args->atom.atom);
2976 break;
2977 case PRINT_FIELD:
2978 printf("REC->%s", args->field.name);
2979 break;
2980 case PRINT_FLAGS:
2981 printf("__print_flags(");
2982 print_args(args->flags.field);
2983 printf(", %s, ", args->flags.delim);
2984 print_fields(args->flags.flags);
2985 printf(")");
2986 break;
2987 case PRINT_SYMBOL:
2988 printf("__print_symbolic(");
2989 print_args(args->symbol.field);
2990 printf(", ");
2991 print_fields(args->symbol.symbols);
2992 printf(")");
2993 break;
2994 case PRINT_STRING:
2995 printf("__get_str(%s)", args->string.string);
2996 break;
2997 case PRINT_TYPE:
2998 printf("(%s)", args->typecast.type);
2999 print_args(args->typecast.item);
3000 break;
3001 case PRINT_OP:
3002 if (strcmp(args->op.op, ":") == 0)
3003 print_paren = 0;
3004 if (print_paren)
3005 printf("(");
3006 print_args(args->op.left);
3007 printf(" %s ", args->op.op);
3008 print_args(args->op.right);
3009 if (print_paren)
3010 printf(")");
3011 break;
3012 default:
3013 /* we should warn... */
3014 return;
3015 }
3016 if (args->next) {
3017 printf("\n");
3018 print_args(args->next);
3019 }
3020}
3021
3022int parse_ftrace_file(char *buf, unsigned long size)
3023{
3024 struct format_field *field;
3025 struct print_arg *arg, **list;
3026 struct event *event;
3027 int ret;
3028
3029 init_input_buf(buf, size);
3030
3031 event = alloc_event();
3032 if (!event)
3033 return -ENOMEM;
3034
3035 event->flags |= EVENT_FL_ISFTRACE;
3036
3037 event->name = event_read_name();
3038 if (!event->name)
3039 die("failed to read ftrace event name");
3040
3041 if (strcmp(event->name, "function") == 0)
3042 event->flags |= EVENT_FL_ISFUNC;
3043
3044 else if (strcmp(event->name, "funcgraph_entry") == 0)
3045 event->flags |= EVENT_FL_ISFUNCENT;
3046
3047 else if (strcmp(event->name, "funcgraph_exit") == 0)
3048 event->flags |= EVENT_FL_ISFUNCRET;
3049
3050 else if (strcmp(event->name, "bprint") == 0)
3051 event->flags |= EVENT_FL_ISBPRINT;
3052
3053 event->id = event_read_id();
3054 if (event->id < 0)
3055 die("failed to read ftrace event id");
3056
3057 add_event(event);
3058
3059 ret = event_read_format(event);
3060 if (ret < 0)
3061 die("failed to read ftrace event format");
3062
3063 ret = event_read_print(event);
3064 if (ret < 0)
3065 die("failed to read ftrace event print fmt");
3066
3067 /* New ftrace handles args */
3068 if (ret > 0)
3069 return 0;
3070 /*
3071 * The arguments for ftrace files are parsed by the fields.
3072 * Set up the fields as their arguments.
3073 */
3074 list = &event->print_fmt.args;
3075 for (field = event->format.fields; field; field = field->next) {
3076 arg = malloc_or_die(sizeof(*arg));
3077 memset(arg, 0, sizeof(*arg));
3078 *list = arg;
3079 list = &arg->next;
3080 arg->type = PRINT_FIELD;
3081 arg->field.name = field->name;
3082 arg->field.field = field;
3083 }
3084 return 0;
3085}
3086
3087int parse_event_file(char *buf, unsigned long size, char *sys)
3088{
3089 struct event *event;
3090 int ret;
3091
3092 init_input_buf(buf, size);
3093
3094 event = alloc_event();
3095 if (!event)
3096 return -ENOMEM;
3097
3098 event->name = event_read_name();
3099 if (!event->name)
3100 die("failed to read event name");
3101
3102 event->id = event_read_id();
3103 if (event->id < 0)
3104 die("failed to read event id");
3105
3106 ret = event_read_format(event);
3107 if (ret < 0) {
3108 warning("failed to read event format for %s", event->name);
3109 goto event_failed;
3110 }
3111
3112 ret = event_read_print(event);
3113 if (ret < 0) {
3114 warning("failed to read event print fmt for %s", event->name);
3115 goto event_failed;
3116 }
3117
3118 event->system = strdup(sys);
3119
3120#define PRINT_ARGS 0
3121 if (PRINT_ARGS && event->print_fmt.args)
3122 print_args(event->print_fmt.args);
3123
3124 add_event(event);
3125 return 0;
3126
3127 event_failed:
3128 event->flags |= EVENT_FL_FAILED;
3129 /* still add it even if it failed */
3130 add_event(event);
3131 return -1;
3132}
3133
3134void parse_set_info(int nr_cpus, int long_sz)
3135{
3136 cpus = nr_cpus;
3137 long_size = long_sz;
3138}
3139
3140int common_pc(struct scripting_context *context)
3141{
3142 return parse_common_pc(context->event_data);
3143}
3144
3145int common_flags(struct scripting_context *context)
3146{
3147 return parse_common_flags(context->event_data);
3148}
3149
3150int common_lock_depth(struct scripting_context *context)
3151{
3152 return parse_common_lock_depth(context->event_data);
3153}
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c
index b9592e0de8d7..f097e0dd6c5c 100644
--- a/tools/perf/util/trace-event-read.c
+++ b/tools/perf/util/trace-event-read.c
@@ -52,6 +52,16 @@ static unsigned long page_size;
52static ssize_t calc_data_size; 52static ssize_t calc_data_size;
53static bool repipe; 53static bool repipe;
54 54
55static void *malloc_or_die(int size)
56{
57 void *ret;
58
59 ret = malloc(size);
60 if (!ret)
61 die("malloc");
62 return ret;
63}
64
55static int do_read(int fd, void *buf, int size) 65static int do_read(int fd, void *buf, int size)
56{ 66{
57 int rsize = size; 67 int rsize = size;
@@ -109,7 +119,7 @@ static unsigned int read4(void)
109 unsigned int data; 119 unsigned int data;
110 120
111 read_or_die(&data, 4); 121 read_or_die(&data, 4);
112 return __data2host4(data); 122 return __data2host4(perf_pevent, data);
113} 123}
114 124
115static unsigned long long read8(void) 125static unsigned long long read8(void)
@@ -117,7 +127,7 @@ static unsigned long long read8(void)
117 unsigned long long data; 127 unsigned long long data;
118 128
119 read_or_die(&data, 8); 129 read_or_die(&data, 8);
120 return __data2host8(data); 130 return __data2host8(perf_pevent, data);
121} 131}
122 132
123static char *read_string(void) 133static char *read_string(void)
@@ -282,7 +292,7 @@ struct cpu_data {
282 unsigned long long offset; 292 unsigned long long offset;
283 unsigned long long size; 293 unsigned long long size;
284 unsigned long long timestamp; 294 unsigned long long timestamp;
285 struct record *next; 295 struct pevent_record *next;
286 char *page; 296 char *page;
287 int cpu; 297 int cpu;
288 int index; 298 int index;
@@ -367,9 +377,9 @@ static int calc_index(void *ptr, int cpu)
367 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page; 377 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
368} 378}
369 379
370struct record *trace_peek_data(int cpu) 380struct pevent_record *trace_peek_data(int cpu)
371{ 381{
372 struct record *data; 382 struct pevent_record *data;
373 void *page = cpu_data[cpu].page; 383 void *page = cpu_data[cpu].page;
374 int idx = cpu_data[cpu].index; 384 int idx = cpu_data[cpu].index;
375 void *ptr = page + idx; 385 void *ptr = page + idx;
@@ -389,15 +399,15 @@ struct record *trace_peek_data(int cpu)
389 /* FIXME: handle header page */ 399 /* FIXME: handle header page */
390 if (header_page_ts_size != 8) 400 if (header_page_ts_size != 8)
391 die("expected a long long type for timestamp"); 401 die("expected a long long type for timestamp");
392 cpu_data[cpu].timestamp = data2host8(ptr); 402 cpu_data[cpu].timestamp = data2host8(perf_pevent, ptr);
393 ptr += 8; 403 ptr += 8;
394 switch (header_page_size_size) { 404 switch (header_page_size_size) {
395 case 4: 405 case 4:
396 cpu_data[cpu].page_size = data2host4(ptr); 406 cpu_data[cpu].page_size = data2host4(perf_pevent, ptr);
397 ptr += 4; 407 ptr += 4;
398 break; 408 break;
399 case 8: 409 case 8:
400 cpu_data[cpu].page_size = data2host8(ptr); 410 cpu_data[cpu].page_size = data2host8(perf_pevent, ptr);
401 ptr += 8; 411 ptr += 8;
402 break; 412 break;
403 default: 413 default:
@@ -414,7 +424,7 @@ read_again:
414 return trace_peek_data(cpu); 424 return trace_peek_data(cpu);
415 } 425 }
416 426
417 type_len_ts = data2host4(ptr); 427 type_len_ts = data2host4(perf_pevent, ptr);
418 ptr += 4; 428 ptr += 4;
419 429
420 type_len = type_len4host(type_len_ts); 430 type_len = type_len4host(type_len_ts);
@@ -424,14 +434,14 @@ read_again:
424 case RINGBUF_TYPE_PADDING: 434 case RINGBUF_TYPE_PADDING:
425 if (!delta) 435 if (!delta)
426 die("error, hit unexpected end of page"); 436 die("error, hit unexpected end of page");
427 length = data2host4(ptr); 437 length = data2host4(perf_pevent, ptr);
428 ptr += 4; 438 ptr += 4;
429 length *= 4; 439 length *= 4;
430 ptr += length; 440 ptr += length;
431 goto read_again; 441 goto read_again;
432 442
433 case RINGBUF_TYPE_TIME_EXTEND: 443 case RINGBUF_TYPE_TIME_EXTEND:
434 extend = data2host4(ptr); 444 extend = data2host4(perf_pevent, ptr);
435 ptr += 4; 445 ptr += 4;
436 extend <<= TS_SHIFT; 446 extend <<= TS_SHIFT;
437 extend += delta; 447 extend += delta;
@@ -442,7 +452,7 @@ read_again:
442 ptr += 12; 452 ptr += 12;
443 break; 453 break;
444 case 0: 454 case 0:
445 length = data2host4(ptr); 455 length = data2host4(perf_pevent, ptr);
446 ptr += 4; 456 ptr += 4;
447 die("here! length=%d", length); 457 die("here! length=%d", length);
448 break; 458 break;
@@ -467,9 +477,9 @@ read_again:
467 return data; 477 return data;
468} 478}
469 479
470struct record *trace_read_data(int cpu) 480struct pevent_record *trace_read_data(int cpu)
471{ 481{
472 struct record *data; 482 struct pevent_record *data;
473 483
474 data = trace_peek_data(cpu); 484 data = trace_peek_data(cpu);
475 cpu_data[cpu].next = NULL; 485 cpu_data[cpu].next = NULL;
@@ -509,6 +519,8 @@ ssize_t trace_report(int fd, bool __repipe)
509 file_bigendian = buf[0]; 519 file_bigendian = buf[0];
510 host_bigendian = bigendian(); 520 host_bigendian = bigendian();
511 521
522 read_trace_init(file_bigendian, host_bigendian);
523
512 read_or_die(buf, 1); 524 read_or_die(buf, 1);
513 long_size = buf[0]; 525 long_size = buf[0];
514 526
@@ -526,11 +538,11 @@ ssize_t trace_report(int fd, bool __repipe)
526 repipe = false; 538 repipe = false;
527 539
528 if (show_funcs) { 540 if (show_funcs) {
529 print_funcs(); 541 pevent_print_funcs(perf_pevent);
530 return size; 542 return size;
531 } 543 }
532 if (show_printk) { 544 if (show_printk) {
533 print_printk(); 545 pevent_print_printk(perf_pevent);
534 return size; 546 return size;
535 } 547 }
536 548
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index 58ae14c5baac..639852ac1117 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -1,20 +1,21 @@
1#ifndef __PERF_TRACE_EVENTS_H 1#ifndef _PERF_UTIL_TRACE_EVENT_H
2#define __PERF_TRACE_EVENTS_H 2#define _PERF_UTIL_TRACE_EVENT_H
3 3
4#include <stdbool.h>
5#include "parse-events.h" 4#include "parse-events.h"
5#include "event-parse.h"
6#include "session.h"
6 7
7struct machine; 8struct machine;
8struct perf_sample; 9struct perf_sample;
9union perf_event; 10union perf_event;
10struct thread; 11struct thread;
11 12
12#define __unused __attribute__((unused)) 13extern int header_page_size_size;
13 14extern int header_page_ts_size;
15extern int header_page_data_offset;
14 16
15#ifndef PAGE_MASK 17extern bool latency_format;
16#define PAGE_MASK (page_size - 1) 18extern struct pevent *perf_pevent;
17#endif
18 19
19enum { 20enum {
20 RINGBUF_TYPE_PADDING = 29, 21 RINGBUF_TYPE_PADDING = 29,
@@ -26,246 +27,37 @@ enum {
26#define TS_SHIFT 27 27#define TS_SHIFT 27
27#endif 28#endif
28 29
29#define NSECS_PER_SEC 1000000000ULL 30int bigendian(void);
30#define NSECS_PER_USEC 1000ULL
31
32enum format_flags {
33 FIELD_IS_ARRAY = 1,
34 FIELD_IS_POINTER = 2,
35 FIELD_IS_SIGNED = 4,
36 FIELD_IS_STRING = 8,
37 FIELD_IS_DYNAMIC = 16,
38 FIELD_IS_FLAG = 32,
39 FIELD_IS_SYMBOLIC = 64,
40};
41
42struct format_field {
43 struct format_field *next;
44 char *type;
45 char *name;
46 int offset;
47 int size;
48 unsigned long flags;
49};
50
51struct format {
52 int nr_common;
53 int nr_fields;
54 struct format_field *common_fields;
55 struct format_field *fields;
56};
57
58struct print_arg_atom {
59 char *atom;
60};
61
62struct print_arg_string {
63 char *string;
64 int offset;
65};
66
67struct print_arg_field {
68 char *name;
69 struct format_field *field;
70};
71
72struct print_flag_sym {
73 struct print_flag_sym *next;
74 char *value;
75 char *str;
76};
77
78struct print_arg_typecast {
79 char *type;
80 struct print_arg *item;
81};
82
83struct print_arg_flags {
84 struct print_arg *field;
85 char *delim;
86 struct print_flag_sym *flags;
87};
88
89struct print_arg_symbol {
90 struct print_arg *field;
91 struct print_flag_sym *symbols;
92};
93
94struct print_arg;
95
96struct print_arg_op {
97 char *op;
98 int prio;
99 struct print_arg *left;
100 struct print_arg *right;
101};
102
103struct print_arg_func {
104 char *name;
105 struct print_arg *args;
106};
107
108enum print_arg_type {
109 PRINT_NULL,
110 PRINT_ATOM,
111 PRINT_FIELD,
112 PRINT_FLAGS,
113 PRINT_SYMBOL,
114 PRINT_TYPE,
115 PRINT_STRING,
116 PRINT_OP,
117};
118
119struct print_arg {
120 struct print_arg *next;
121 enum print_arg_type type;
122 union {
123 struct print_arg_atom atom;
124 struct print_arg_field field;
125 struct print_arg_typecast typecast;
126 struct print_arg_flags flags;
127 struct print_arg_symbol symbol;
128 struct print_arg_func func;
129 struct print_arg_string string;
130 struct print_arg_op op;
131 };
132};
133
134struct print_fmt {
135 char *format;
136 struct print_arg *args;
137};
138
139struct event {
140 struct event *next;
141 char *name;
142 int id;
143 int flags;
144 struct format format;
145 struct print_fmt print_fmt;
146 char *system;
147};
148
149enum {
150 EVENT_FL_ISFTRACE = 0x01,
151 EVENT_FL_ISPRINT = 0x02,
152 EVENT_FL_ISBPRINT = 0x04,
153 EVENT_FL_ISFUNC = 0x08,
154 EVENT_FL_ISFUNCENT = 0x10,
155 EVENT_FL_ISFUNCRET = 0x20,
156
157 EVENT_FL_FAILED = 0x80000000
158};
159
160struct record {
161 unsigned long long ts;
162 int size;
163 void *data;
164};
165
166struct record *trace_peek_data(int cpu);
167struct record *trace_read_data(int cpu);
168
169void parse_set_info(int nr_cpus, int long_sz);
170
171ssize_t trace_report(int fd, bool repipe);
172
173void *malloc_or_die(unsigned int size);
174 31
175void parse_cmdlines(char *file, int size); 32int read_trace_init(int file_bigendian, int host_bigendian);
176void parse_proc_kallsyms(char *file, unsigned int size); 33void print_trace_event(int cpu, void *data, int size);
177void parse_ftrace_printk(char *file, unsigned int size);
178 34
179void print_funcs(void); 35void print_event(int cpu, void *data, int size, unsigned long long nsecs,
180void print_printk(void); 36 char *comm);
181 37
182int parse_ftrace_file(char *buf, unsigned long size); 38int parse_ftrace_file(char *buf, unsigned long size);
183int parse_event_file(char *buf, unsigned long size, char *sys); 39int parse_event_file(char *buf, unsigned long size, char *sys);
184void print_trace_event(int cpu, void *data, int size);
185
186extern int file_bigendian;
187extern int host_bigendian;
188
189int bigendian(void);
190
191static inline unsigned short __data2host2(unsigned short data)
192{
193 unsigned short swap;
194
195 if (host_bigendian == file_bigendian)
196 return data;
197 40
198 swap = ((data & 0xffULL) << 8) | 41struct pevent_record *trace_peek_data(int cpu);
199 ((data & (0xffULL << 8)) >> 8); 42struct event_format *trace_find_event(int type);
200 43
201 return swap; 44unsigned long long
202} 45raw_field_value(struct event_format *event, const char *name, void *data);
203 46void *raw_field_ptr(struct event_format *event, const char *name, void *data);
204static inline unsigned int __data2host4(unsigned int data)
205{
206 unsigned int swap;
207
208 if (host_bigendian == file_bigendian)
209 return data;
210
211 swap = ((data & 0xffULL) << 24) |
212 ((data & (0xffULL << 8)) << 8) |
213 ((data & (0xffULL << 16)) >> 8) |
214 ((data & (0xffULL << 24)) >> 24);
215
216 return swap;
217}
218
219static inline unsigned long long __data2host8(unsigned long long data)
220{
221 unsigned long long swap;
222
223 if (host_bigendian == file_bigendian)
224 return data;
225
226 swap = ((data & 0xffULL) << 56) |
227 ((data & (0xffULL << 8)) << 40) |
228 ((data & (0xffULL << 16)) << 24) |
229 ((data & (0xffULL << 24)) << 8) |
230 ((data & (0xffULL << 32)) >> 8) |
231 ((data & (0xffULL << 40)) >> 24) |
232 ((data & (0xffULL << 48)) >> 40) |
233 ((data & (0xffULL << 56)) >> 56);
234
235 return swap;
236}
237 47
238#define data2host2(ptr) __data2host2(*(unsigned short *)ptr) 48void parse_proc_kallsyms(char *file, unsigned int size __unused);
239#define data2host4(ptr) __data2host4(*(unsigned int *)ptr) 49void parse_ftrace_printk(char *file, unsigned int size __unused);
240#define data2host8(ptr) ({ \
241 unsigned long long __val; \
242 \
243 memcpy(&__val, (ptr), sizeof(unsigned long long)); \
244 __data2host8(__val); \
245})
246 50
247extern int header_page_ts_offset; 51ssize_t trace_report(int fd, bool repipe);
248extern int header_page_ts_size;
249extern int header_page_size_offset;
250extern int header_page_size_size;
251extern int header_page_data_offset;
252extern int header_page_data_size;
253
254extern bool latency_format;
255 52
256int trace_parse_common_type(void *data); 53int trace_parse_common_type(void *data);
257int trace_parse_common_pid(void *data); 54int trace_parse_common_pid(void *data);
258int parse_common_pc(void *data); 55
259int parse_common_flags(void *data); 56struct event_format *trace_find_next_event(struct event_format *event);
260int parse_common_lock_depth(void *data);
261struct event *trace_find_event(int id);
262struct event *trace_find_next_event(struct event *event);
263unsigned long long read_size(void *ptr, int size); 57unsigned long long read_size(void *ptr, int size);
264unsigned long long
265raw_field_value(struct event *event, const char *name, void *data);
266void *raw_field_ptr(struct event *event, const char *name, void *data);
267unsigned long long eval_flag(const char *flag); 58unsigned long long eval_flag(const char *flag);
268 59
60struct pevent_record *trace_read_data(int cpu);
269int read_tracing_data(int fd, struct list_head *pattrs); 61int read_tracing_data(int fd, struct list_head *pattrs);
270 62
271struct tracing_data { 63struct tracing_data {
@@ -280,15 +72,6 @@ struct tracing_data *tracing_data_get(struct list_head *pattrs,
280void tracing_data_put(struct tracing_data *tdata); 72void tracing_data_put(struct tracing_data *tdata);
281 73
282 74
283/* taken from kernel/trace/trace.h */
284enum trace_flag_type {
285 TRACE_FLAG_IRQS_OFF = 0x01,
286 TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
287 TRACE_FLAG_NEED_RESCHED = 0x04,
288 TRACE_FLAG_HARDIRQ = 0x08,
289 TRACE_FLAG_SOFTIRQ = 0x10,
290};
291
292struct scripting_ops { 75struct scripting_ops {
293 const char *name; 76 const char *name;
294 int (*start_script) (const char *script, int argc, const char **argv); 77 int (*start_script) (const char *script, int argc, const char **argv);
@@ -314,4 +97,4 @@ int common_pc(struct scripting_context *context);
314int common_flags(struct scripting_context *context); 97int common_flags(struct scripting_context *context);
315int common_lock_depth(struct scripting_context *context); 98int common_lock_depth(struct scripting_context *context);
316 99
317#endif /* __PERF_TRACE_EVENTS_H */ 100#endif /* _PERF_UTIL_TRACE_EVENT_H */
diff --git a/tools/perf/util/types.h b/tools/perf/util/types.h
index 5f3689a3d085..c51fa6b70a28 100644
--- a/tools/perf/util/types.h
+++ b/tools/perf/util/types.h
@@ -16,4 +16,9 @@ typedef signed short s16;
16typedef unsigned char u8; 16typedef unsigned char u8;
17typedef signed char s8; 17typedef signed char s8;
18 18
19union u64_swap {
20 u64 val64;
21 u32 val32[2];
22};
23
19#endif /* __PERF_TYPES_H */ 24#endif /* __PERF_TYPES_H */
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c
deleted file mode 100644
index 556829124b02..000000000000
--- a/tools/perf/util/ui/browser.c
+++ /dev/null
@@ -1,597 +0,0 @@
1#include "../util.h"
2#include "../cache.h"
3#include "../../perf.h"
4#include "libslang.h"
5#include <newt.h>
6#include "ui.h"
7#include "util.h"
8#include <linux/compiler.h>
9#include <linux/list.h>
10#include <linux/rbtree.h>
11#include <stdlib.h>
12#include <sys/ttydefaults.h>
13#include "browser.h"
14#include "helpline.h"
15#include "keysyms.h"
16#include "../color.h"
17
18static int ui_browser__percent_color(struct ui_browser *browser,
19 double percent, bool current)
20{
21 if (current && (!browser->use_navkeypressed || browser->navkeypressed))
22 return HE_COLORSET_SELECTED;
23 if (percent >= MIN_RED)
24 return HE_COLORSET_TOP;
25 if (percent >= MIN_GREEN)
26 return HE_COLORSET_MEDIUM;
27 return HE_COLORSET_NORMAL;
28}
29
30void ui_browser__set_color(struct ui_browser *self __used, int color)
31{
32 SLsmg_set_color(color);
33}
34
35void ui_browser__set_percent_color(struct ui_browser *self,
36 double percent, bool current)
37{
38 int color = ui_browser__percent_color(self, percent, current);
39 ui_browser__set_color(self, color);
40}
41
42void ui_browser__gotorc(struct ui_browser *self, int y, int x)
43{
44 SLsmg_gotorc(self->y + y, self->x + x);
45}
46
47static struct list_head *
48ui_browser__list_head_filter_entries(struct ui_browser *browser,
49 struct list_head *pos)
50{
51 do {
52 if (!browser->filter || !browser->filter(browser, pos))
53 return pos;
54 pos = pos->next;
55 } while (pos != browser->entries);
56
57 return NULL;
58}
59
60static struct list_head *
61ui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
62 struct list_head *pos)
63{
64 do {
65 if (!browser->filter || !browser->filter(browser, pos))
66 return pos;
67 pos = pos->prev;
68 } while (pos != browser->entries);
69
70 return NULL;
71}
72
73void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
74{
75 struct list_head *head = self->entries;
76 struct list_head *pos;
77
78 if (self->nr_entries == 0)
79 return;
80
81 switch (whence) {
82 case SEEK_SET:
83 pos = ui_browser__list_head_filter_entries(self, head->next);
84 break;
85 case SEEK_CUR:
86 pos = self->top;
87 break;
88 case SEEK_END:
89 pos = ui_browser__list_head_filter_prev_entries(self, head->prev);
90 break;
91 default:
92 return;
93 }
94
95 assert(pos != NULL);
96
97 if (offset > 0) {
98 while (offset-- != 0)
99 pos = ui_browser__list_head_filter_entries(self, pos->next);
100 } else {
101 while (offset++ != 0)
102 pos = ui_browser__list_head_filter_prev_entries(self, pos->prev);
103 }
104
105 self->top = pos;
106}
107
108void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence)
109{
110 struct rb_root *root = self->entries;
111 struct rb_node *nd;
112
113 switch (whence) {
114 case SEEK_SET:
115 nd = rb_first(root);
116 break;
117 case SEEK_CUR:
118 nd = self->top;
119 break;
120 case SEEK_END:
121 nd = rb_last(root);
122 break;
123 default:
124 return;
125 }
126
127 if (offset > 0) {
128 while (offset-- != 0)
129 nd = rb_next(nd);
130 } else {
131 while (offset++ != 0)
132 nd = rb_prev(nd);
133 }
134
135 self->top = nd;
136}
137
138unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self)
139{
140 struct rb_node *nd;
141 int row = 0;
142
143 if (self->top == NULL)
144 self->top = rb_first(self->entries);
145
146 nd = self->top;
147
148 while (nd != NULL) {
149 ui_browser__gotorc(self, row, 0);
150 self->write(self, nd, row);
151 if (++row == self->height)
152 break;
153 nd = rb_next(nd);
154 }
155
156 return row;
157}
158
159bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
160{
161 return self->top_idx + row == self->index;
162}
163
164void ui_browser__refresh_dimensions(struct ui_browser *self)
165{
166 self->width = SLtt_Screen_Cols - 1;
167 self->height = SLtt_Screen_Rows - 2;
168 self->y = 1;
169 self->x = 0;
170}
171
172void ui_browser__handle_resize(struct ui_browser *browser)
173{
174 ui__refresh_dimensions(false);
175 ui_browser__show(browser, browser->title, ui_helpline__current);
176 ui_browser__refresh(browser);
177}
178
179int ui_browser__warning(struct ui_browser *browser, int timeout,
180 const char *format, ...)
181{
182 va_list args;
183 char *text;
184 int key = 0, err;
185
186 va_start(args, format);
187 err = vasprintf(&text, format, args);
188 va_end(args);
189
190 if (err < 0) {
191 va_start(args, format);
192 ui_helpline__vpush(format, args);
193 va_end(args);
194 } else {
195 while ((key == ui__question_window("Warning!", text,
196 "Press any key...",
197 timeout)) == K_RESIZE)
198 ui_browser__handle_resize(browser);
199 free(text);
200 }
201
202 return key;
203}
204
205int ui_browser__help_window(struct ui_browser *browser, const char *text)
206{
207 int key;
208
209 while ((key = ui__help_window(text)) == K_RESIZE)
210 ui_browser__handle_resize(browser);
211
212 return key;
213}
214
215bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text)
216{
217 int key;
218
219 while ((key = ui__dialog_yesno(text)) == K_RESIZE)
220 ui_browser__handle_resize(browser);
221
222 return key == K_ENTER || toupper(key) == 'Y';
223}
224
225void ui_browser__reset_index(struct ui_browser *self)
226{
227 self->index = self->top_idx = 0;
228 self->seek(self, 0, SEEK_SET);
229}
230
231void __ui_browser__show_title(struct ui_browser *browser, const char *title)
232{
233 SLsmg_gotorc(0, 0);
234 ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
235 slsmg_write_nstring(title, browser->width + 1);
236}
237
238void ui_browser__show_title(struct ui_browser *browser, const char *title)
239{
240 pthread_mutex_lock(&ui__lock);
241 __ui_browser__show_title(browser, title);
242 pthread_mutex_unlock(&ui__lock);
243}
244
245int ui_browser__show(struct ui_browser *self, const char *title,
246 const char *helpline, ...)
247{
248 int err;
249 va_list ap;
250
251 ui_browser__refresh_dimensions(self);
252
253 pthread_mutex_lock(&ui__lock);
254 __ui_browser__show_title(self, title);
255
256 self->title = title;
257 free(self->helpline);
258 self->helpline = NULL;
259
260 va_start(ap, helpline);
261 err = vasprintf(&self->helpline, helpline, ap);
262 va_end(ap);
263 if (err > 0)
264 ui_helpline__push(self->helpline);
265 pthread_mutex_unlock(&ui__lock);
266 return err ? 0 : -1;
267}
268
269void ui_browser__hide(struct ui_browser *browser __used)
270{
271 pthread_mutex_lock(&ui__lock);
272 ui_helpline__pop();
273 pthread_mutex_unlock(&ui__lock);
274}
275
276static void ui_browser__scrollbar_set(struct ui_browser *browser)
277{
278 int height = browser->height, h = 0, pct = 0,
279 col = browser->width,
280 row = browser->y - 1;
281
282 if (browser->nr_entries > 1) {
283 pct = ((browser->index * (browser->height - 1)) /
284 (browser->nr_entries - 1));
285 }
286
287 SLsmg_set_char_set(1);
288
289 while (h < height) {
290 ui_browser__gotorc(browser, row++, col);
291 SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_CKBRD_CHAR);
292 ++h;
293 }
294
295 SLsmg_set_char_set(0);
296}
297
298static int __ui_browser__refresh(struct ui_browser *browser)
299{
300 int row;
301 int width = browser->width;
302
303 row = browser->refresh(browser);
304 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
305
306 if (!browser->use_navkeypressed || browser->navkeypressed)
307 ui_browser__scrollbar_set(browser);
308 else
309 width += 1;
310
311 SLsmg_fill_region(browser->y + row, browser->x,
312 browser->height - row, width, ' ');
313
314 return 0;
315}
316
317int ui_browser__refresh(struct ui_browser *browser)
318{
319 pthread_mutex_lock(&ui__lock);
320 __ui_browser__refresh(browser);
321 pthread_mutex_unlock(&ui__lock);
322
323 return 0;
324}
325
326/*
327 * Here we're updating nr_entries _after_ we started browsing, i.e. we have to
328 * forget about any reference to any entry in the underlying data structure,
329 * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser
330 * after an output_resort and hist decay.
331 */
332void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
333{
334 off_t offset = nr_entries - browser->nr_entries;
335
336 browser->nr_entries = nr_entries;
337
338 if (offset < 0) {
339 if (browser->top_idx < (u64)-offset)
340 offset = -browser->top_idx;
341
342 browser->index += offset;
343 browser->top_idx += offset;
344 }
345
346 browser->top = NULL;
347 browser->seek(browser, browser->top_idx, SEEK_SET);
348}
349
350int ui_browser__run(struct ui_browser *self, int delay_secs)
351{
352 int err, key;
353
354 while (1) {
355 off_t offset;
356
357 pthread_mutex_lock(&ui__lock);
358 err = __ui_browser__refresh(self);
359 SLsmg_refresh();
360 pthread_mutex_unlock(&ui__lock);
361 if (err < 0)
362 break;
363
364 key = ui__getch(delay_secs);
365
366 if (key == K_RESIZE) {
367 ui__refresh_dimensions(false);
368 ui_browser__refresh_dimensions(self);
369 __ui_browser__show_title(self, self->title);
370 ui_helpline__puts(self->helpline);
371 continue;
372 }
373
374 if (self->use_navkeypressed && !self->navkeypressed) {
375 if (key == K_DOWN || key == K_UP ||
376 key == K_PGDN || key == K_PGUP ||
377 key == K_HOME || key == K_END ||
378 key == ' ') {
379 self->navkeypressed = true;
380 continue;
381 } else
382 return key;
383 }
384
385 switch (key) {
386 case K_DOWN:
387 if (self->index == self->nr_entries - 1)
388 break;
389 ++self->index;
390 if (self->index == self->top_idx + self->height) {
391 ++self->top_idx;
392 self->seek(self, +1, SEEK_CUR);
393 }
394 break;
395 case K_UP:
396 if (self->index == 0)
397 break;
398 --self->index;
399 if (self->index < self->top_idx) {
400 --self->top_idx;
401 self->seek(self, -1, SEEK_CUR);
402 }
403 break;
404 case K_PGDN:
405 case ' ':
406 if (self->top_idx + self->height > self->nr_entries - 1)
407 break;
408
409 offset = self->height;
410 if (self->index + offset > self->nr_entries - 1)
411 offset = self->nr_entries - 1 - self->index;
412 self->index += offset;
413 self->top_idx += offset;
414 self->seek(self, +offset, SEEK_CUR);
415 break;
416 case K_PGUP:
417 if (self->top_idx == 0)
418 break;
419
420 if (self->top_idx < self->height)
421 offset = self->top_idx;
422 else
423 offset = self->height;
424
425 self->index -= offset;
426 self->top_idx -= offset;
427 self->seek(self, -offset, SEEK_CUR);
428 break;
429 case K_HOME:
430 ui_browser__reset_index(self);
431 break;
432 case K_END:
433 offset = self->height - 1;
434 if (offset >= self->nr_entries)
435 offset = self->nr_entries - 1;
436
437 self->index = self->nr_entries - 1;
438 self->top_idx = self->index - offset;
439 self->seek(self, -offset, SEEK_END);
440 break;
441 default:
442 return key;
443 }
444 }
445 return -1;
446}
447
448unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
449{
450 struct list_head *pos;
451 struct list_head *head = self->entries;
452 int row = 0;
453
454 if (self->top == NULL || self->top == self->entries)
455 self->top = ui_browser__list_head_filter_entries(self, head->next);
456
457 pos = self->top;
458
459 list_for_each_from(pos, head) {
460 if (!self->filter || !self->filter(self, pos)) {
461 ui_browser__gotorc(self, row, 0);
462 self->write(self, pos, row);
463 if (++row == self->height)
464 break;
465 }
466 }
467
468 return row;
469}
470
471static struct ui_browser__colorset {
472 const char *name, *fg, *bg;
473 int colorset;
474} ui_browser__colorsets[] = {
475 {
476 .colorset = HE_COLORSET_TOP,
477 .name = "top",
478 .fg = "red",
479 .bg = "default",
480 },
481 {
482 .colorset = HE_COLORSET_MEDIUM,
483 .name = "medium",
484 .fg = "green",
485 .bg = "default",
486 },
487 {
488 .colorset = HE_COLORSET_NORMAL,
489 .name = "normal",
490 .fg = "default",
491 .bg = "default",
492 },
493 {
494 .colorset = HE_COLORSET_SELECTED,
495 .name = "selected",
496 .fg = "black",
497 .bg = "lightgray",
498 },
499 {
500 .colorset = HE_COLORSET_CODE,
501 .name = "code",
502 .fg = "blue",
503 .bg = "default",
504 },
505 {
506 .name = NULL,
507 }
508};
509
510
511static int ui_browser__color_config(const char *var, const char *value,
512 void *data __used)
513{
514 char *fg = NULL, *bg;
515 int i;
516
517 /* same dir for all commands */
518 if (prefixcmp(var, "colors.") != 0)
519 return 0;
520
521 for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) {
522 const char *name = var + 7;
523
524 if (strcmp(ui_browser__colorsets[i].name, name) != 0)
525 continue;
526
527 fg = strdup(value);
528 if (fg == NULL)
529 break;
530
531 bg = strchr(fg, ',');
532 if (bg == NULL)
533 break;
534
535 *bg = '\0';
536 while (isspace(*++bg));
537 ui_browser__colorsets[i].bg = bg;
538 ui_browser__colorsets[i].fg = fg;
539 return 0;
540 }
541
542 free(fg);
543 return -1;
544}
545
546void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence)
547{
548 switch (whence) {
549 case SEEK_SET:
550 browser->top = browser->entries;
551 break;
552 case SEEK_CUR:
553 browser->top = browser->top + browser->top_idx + offset;
554 break;
555 case SEEK_END:
556 browser->top = browser->top + browser->nr_entries + offset;
557 break;
558 default:
559 return;
560 }
561}
562
563unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
564{
565 unsigned int row = 0, idx = browser->top_idx;
566 char **pos;
567
568 if (browser->top == NULL)
569 browser->top = browser->entries;
570
571 pos = (char **)browser->top;
572 while (idx < browser->nr_entries) {
573 if (!browser->filter || !browser->filter(browser, *pos)) {
574 ui_browser__gotorc(browser, row, 0);
575 browser->write(browser, pos, row);
576 if (++row == browser->height)
577 break;
578 }
579
580 ++idx;
581 ++pos;
582 }
583
584 return row;
585}
586
587void ui_browser__init(void)
588{
589 int i = 0;
590
591 perf_config(ui_browser__color_config, NULL);
592
593 while (ui_browser__colorsets[i].name) {
594 struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
595 sltt_set_color(c->colorset, c->name, c->fg, c->bg);
596 }
597}
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
deleted file mode 100644
index 6ee82f60feaf..000000000000
--- a/tools/perf/util/ui/browser.h
+++ /dev/null
@@ -1,65 +0,0 @@
1#ifndef _PERF_UI_BROWSER_H_
2#define _PERF_UI_BROWSER_H_ 1
3
4#include <stdbool.h>
5#include <sys/types.h>
6#include "../types.h"
7
8#define HE_COLORSET_TOP 50
9#define HE_COLORSET_MEDIUM 51
10#define HE_COLORSET_NORMAL 52
11#define HE_COLORSET_SELECTED 53
12#define HE_COLORSET_CODE 54
13
14struct ui_browser {
15 u64 index, top_idx;
16 void *top, *entries;
17 u16 y, x, width, height;
18 void *priv;
19 const char *title;
20 char *helpline;
21 unsigned int (*refresh)(struct ui_browser *self);
22 void (*write)(struct ui_browser *self, void *entry, int row);
23 void (*seek)(struct ui_browser *self, off_t offset, int whence);
24 bool (*filter)(struct ui_browser *self, void *entry);
25 u32 nr_entries;
26 bool navkeypressed;
27 bool use_navkeypressed;
28};
29
30void ui_browser__set_color(struct ui_browser *self, int color);
31void ui_browser__set_percent_color(struct ui_browser *self,
32 double percent, bool current);
33bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row);
34void ui_browser__refresh_dimensions(struct ui_browser *self);
35void ui_browser__reset_index(struct ui_browser *self);
36
37void ui_browser__gotorc(struct ui_browser *self, int y, int x);
38void __ui_browser__show_title(struct ui_browser *browser, const char *title);
39void ui_browser__show_title(struct ui_browser *browser, const char *title);
40int ui_browser__show(struct ui_browser *self, const char *title,
41 const char *helpline, ...);
42void ui_browser__hide(struct ui_browser *self);
43int ui_browser__refresh(struct ui_browser *self);
44int ui_browser__run(struct ui_browser *browser, int delay_secs);
45void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);
46void ui_browser__handle_resize(struct ui_browser *browser);
47
48int ui_browser__warning(struct ui_browser *browser, int timeout,
49 const char *format, ...);
50int ui_browser__help_window(struct ui_browser *browser, const char *text);
51bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
52int ui_browser__input_window(const char *title, const char *text, char *input,
53 const char *exit_msg, int delay_sec);
54
55void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
56unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
57
58void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence);
59unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self);
60
61void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence);
62unsigned int ui_browser__list_head_refresh(struct ui_browser *self);
63
64void ui_browser__init(void);
65#endif /* _PERF_UI_BROWSER_H_ */
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
deleted file mode 100644
index 57a4c6ef3fd2..000000000000
--- a/tools/perf/util/ui/browsers/annotate.c
+++ /dev/null
@@ -1,433 +0,0 @@
1#include "../../util.h"
2#include "../browser.h"
3#include "../helpline.h"
4#include "../libslang.h"
5#include "../ui.h"
6#include "../util.h"
7#include "../../annotate.h"
8#include "../../hist.h"
9#include "../../sort.h"
10#include "../../symbol.h"
11#include <pthread.h>
12#include <newt.h>
13
14struct annotate_browser {
15 struct ui_browser b;
16 struct rb_root entries;
17 struct rb_node *curr_hot;
18 struct objdump_line *selection;
19 int nr_asm_entries;
20 int nr_entries;
21 bool hide_src_code;
22};
23
24struct objdump_line_rb_node {
25 struct rb_node rb_node;
26 double percent;
27 u32 idx;
28 int idx_asm;
29};
30
31static inline
32struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
33{
34 return (struct objdump_line_rb_node *)(self + 1);
35}
36
37static bool objdump_line__filter(struct ui_browser *browser, void *entry)
38{
39 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
40
41 if (ab->hide_src_code) {
42 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
43 return ol->offset == -1;
44 }
45
46 return false;
47}
48
49static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
50{
51 struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
52 struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
53 bool current_entry = ui_browser__is_current_entry(self, row);
54 int width = self->width;
55
56 if (ol->offset != -1) {
57 struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
58 ui_browser__set_percent_color(self, olrb->percent, current_entry);
59 slsmg_printf(" %7.2f ", olrb->percent);
60 } else {
61 ui_browser__set_percent_color(self, 0, current_entry);
62 slsmg_write_nstring(" ", 9);
63 }
64
65 SLsmg_write_char(':');
66 slsmg_write_nstring(" ", 8);
67
68 /* The scroll bar isn't being used */
69 if (!self->navkeypressed)
70 width += 1;
71
72 if (!ab->hide_src_code && ol->offset != -1)
73 if (!current_entry || (self->use_navkeypressed &&
74 !self->navkeypressed))
75 ui_browser__set_color(self, HE_COLORSET_CODE);
76
77 if (!*ol->line)
78 slsmg_write_nstring(" ", width - 18);
79 else
80 slsmg_write_nstring(ol->line, width - 18);
81
82 if (current_entry)
83 ab->selection = ol;
84}
85
86static double objdump_line__calc_percent(struct objdump_line *self,
87 struct symbol *sym, int evidx)
88{
89 double percent = 0.0;
90
91 if (self->offset != -1) {
92 int len = sym->end - sym->start;
93 unsigned int hits = 0;
94 struct annotation *notes = symbol__annotation(sym);
95 struct source_line *src_line = notes->src->lines;
96 struct sym_hist *h = annotation__histogram(notes, evidx);
97 s64 offset = self->offset;
98 struct objdump_line *next;
99
100 next = objdump__get_next_ip_line(&notes->src->source, self);
101 while (offset < (s64)len &&
102 (next == NULL || offset < next->offset)) {
103 if (src_line) {
104 percent += src_line[offset].percent;
105 } else
106 hits += h->addr[offset];
107
108 ++offset;
109 }
110 /*
111 * If the percentage wasn't already calculated in
112 * symbol__get_source_line, do it now:
113 */
114 if (src_line == NULL && h->sum)
115 percent = 100.0 * hits / h->sum;
116 }
117
118 return percent;
119}
120
121static void objdump__insert_line(struct rb_root *self,
122 struct objdump_line_rb_node *line)
123{
124 struct rb_node **p = &self->rb_node;
125 struct rb_node *parent = NULL;
126 struct objdump_line_rb_node *l;
127
128 while (*p != NULL) {
129 parent = *p;
130 l = rb_entry(parent, struct objdump_line_rb_node, rb_node);
131 if (line->percent < l->percent)
132 p = &(*p)->rb_left;
133 else
134 p = &(*p)->rb_right;
135 }
136 rb_link_node(&line->rb_node, parent, p);
137 rb_insert_color(&line->rb_node, self);
138}
139
140static void annotate_browser__set_top(struct annotate_browser *self,
141 struct rb_node *nd)
142{
143 struct objdump_line_rb_node *rbpos;
144 struct objdump_line *pos;
145 unsigned back;
146
147 ui_browser__refresh_dimensions(&self->b);
148 back = self->b.height / 2;
149 rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node);
150 pos = ((struct objdump_line *)rbpos) - 1;
151 self->b.top_idx = self->b.index = rbpos->idx;
152
153 while (self->b.top_idx != 0 && back != 0) {
154 pos = list_entry(pos->node.prev, struct objdump_line, node);
155
156 --self->b.top_idx;
157 --back;
158 }
159
160 self->b.top = pos;
161 self->curr_hot = nd;
162}
163
164static void annotate_browser__calc_percent(struct annotate_browser *browser,
165 int evidx)
166{
167 struct map_symbol *ms = browser->b.priv;
168 struct symbol *sym = ms->sym;
169 struct annotation *notes = symbol__annotation(sym);
170 struct objdump_line *pos;
171
172 browser->entries = RB_ROOT;
173
174 pthread_mutex_lock(&notes->lock);
175
176 list_for_each_entry(pos, &notes->src->source, node) {
177 struct objdump_line_rb_node *rbpos = objdump_line__rb(pos);
178 rbpos->percent = objdump_line__calc_percent(pos, sym, evidx);
179 if (rbpos->percent < 0.01) {
180 RB_CLEAR_NODE(&rbpos->rb_node);
181 continue;
182 }
183 objdump__insert_line(&browser->entries, rbpos);
184 }
185 pthread_mutex_unlock(&notes->lock);
186
187 browser->curr_hot = rb_last(&browser->entries);
188}
189
190static bool annotate_browser__toggle_source(struct annotate_browser *browser)
191{
192 struct objdump_line *ol;
193 struct objdump_line_rb_node *olrb;
194 off_t offset = browser->b.index - browser->b.top_idx;
195
196 browser->b.seek(&browser->b, offset, SEEK_CUR);
197 ol = list_entry(browser->b.top, struct objdump_line, node);
198 olrb = objdump_line__rb(ol);
199
200 if (browser->hide_src_code) {
201 if (olrb->idx_asm < offset)
202 offset = olrb->idx;
203
204 browser->b.nr_entries = browser->nr_entries;
205 browser->hide_src_code = false;
206 browser->b.seek(&browser->b, -offset, SEEK_CUR);
207 browser->b.top_idx = olrb->idx - offset;
208 browser->b.index = olrb->idx;
209 } else {
210 if (olrb->idx_asm < 0) {
211 ui_helpline__puts("Only available for assembly lines.");
212 browser->b.seek(&browser->b, -offset, SEEK_CUR);
213 return false;
214 }
215
216 if (olrb->idx_asm < offset)
217 offset = olrb->idx_asm;
218
219 browser->b.nr_entries = browser->nr_asm_entries;
220 browser->hide_src_code = true;
221 browser->b.seek(&browser->b, -offset, SEEK_CUR);
222 browser->b.top_idx = olrb->idx_asm - offset;
223 browser->b.index = olrb->idx_asm;
224 }
225
226 return true;
227}
228
229static int annotate_browser__run(struct annotate_browser *self, int evidx,
230 void(*timer)(void *arg),
231 void *arg, int delay_secs)
232{
233 struct rb_node *nd = NULL;
234 struct map_symbol *ms = self->b.priv;
235 struct symbol *sym = ms->sym;
236 const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, "
237 "H: Go to hottest line, ->/ENTER: Line action, "
238 "S: Toggle source code view";
239 int key;
240
241 if (ui_browser__show(&self->b, sym->name, help) < 0)
242 return -1;
243
244 annotate_browser__calc_percent(self, evidx);
245
246 if (self->curr_hot)
247 annotate_browser__set_top(self, self->curr_hot);
248
249 nd = self->curr_hot;
250
251 while (1) {
252 key = ui_browser__run(&self->b, delay_secs);
253
254 if (delay_secs != 0) {
255 annotate_browser__calc_percent(self, evidx);
256 /*
257 * Current line focus got out of the list of most active
258 * lines, NULL it so that if TAB|UNTAB is pressed, we
259 * move to curr_hot (current hottest line).
260 */
261 if (nd != NULL && RB_EMPTY_NODE(nd))
262 nd = NULL;
263 }
264
265 switch (key) {
266 case K_TIMER:
267 if (timer != NULL)
268 timer(arg);
269
270 if (delay_secs != 0)
271 symbol__annotate_decay_histogram(sym, evidx);
272 continue;
273 case K_TAB:
274 if (nd != NULL) {
275 nd = rb_prev(nd);
276 if (nd == NULL)
277 nd = rb_last(&self->entries);
278 } else
279 nd = self->curr_hot;
280 break;
281 case K_UNTAB:
282 if (nd != NULL)
283 nd = rb_next(nd);
284 if (nd == NULL)
285 nd = rb_first(&self->entries);
286 else
287 nd = self->curr_hot;
288 break;
289 case 'H':
290 case 'h':
291 nd = self->curr_hot;
292 break;
293 case 'S':
294 case 's':
295 if (annotate_browser__toggle_source(self))
296 ui_helpline__puts(help);
297 continue;
298 case K_ENTER:
299 case K_RIGHT:
300 if (self->selection == NULL) {
301 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
302 continue;
303 }
304
305 if (self->selection->offset == -1) {
306 ui_helpline__puts("Actions are only available for assembly lines.");
307 continue;
308 } else {
309 char *s = strstr(self->selection->line, "callq ");
310 struct annotation *notes;
311 struct symbol *target;
312 u64 ip;
313
314 if (s == NULL) {
315 ui_helpline__puts("Actions are only available for the 'callq' instruction.");
316 continue;
317 }
318
319 s = strchr(s, ' ');
320 if (s++ == NULL) {
321 ui_helpline__puts("Invallid callq instruction.");
322 continue;
323 }
324
325 ip = strtoull(s, NULL, 16);
326 ip = ms->map->map_ip(ms->map, ip);
327 target = map__find_symbol(ms->map, ip, NULL);
328 if (target == NULL) {
329 ui_helpline__puts("The called function was not found.");
330 continue;
331 }
332
333 notes = symbol__annotation(target);
334 pthread_mutex_lock(&notes->lock);
335
336 if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
337 pthread_mutex_unlock(&notes->lock);
338 ui__warning("Not enough memory for annotating '%s' symbol!\n",
339 target->name);
340 continue;
341 }
342
343 pthread_mutex_unlock(&notes->lock);
344 symbol__tui_annotate(target, ms->map, evidx,
345 timer, arg, delay_secs);
346 ui_browser__show_title(&self->b, sym->name);
347 }
348 continue;
349 case K_LEFT:
350 case K_ESC:
351 case 'q':
352 case CTRL('c'):
353 goto out;
354 default:
355 continue;
356 }
357
358 if (nd != NULL)
359 annotate_browser__set_top(self, nd);
360 }
361out:
362 ui_browser__hide(&self->b);
363 return key;
364}
365
366int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
367 void(*timer)(void *arg), void *arg, int delay_secs)
368{
369 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
370 timer, arg, delay_secs);
371}
372
373int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
374 void(*timer)(void *arg), void *arg,
375 int delay_secs)
376{
377 struct objdump_line *pos, *n;
378 struct annotation *notes;
379 struct map_symbol ms = {
380 .map = map,
381 .sym = sym,
382 };
383 struct annotate_browser browser = {
384 .b = {
385 .refresh = ui_browser__list_head_refresh,
386 .seek = ui_browser__list_head_seek,
387 .write = annotate_browser__write,
388 .filter = objdump_line__filter,
389 .priv = &ms,
390 .use_navkeypressed = true,
391 },
392 };
393 int ret;
394
395 if (sym == NULL)
396 return -1;
397
398 if (map->dso->annotate_warned)
399 return -1;
400
401 if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
402 ui__error("%s", ui_helpline__last_msg);
403 return -1;
404 }
405
406 ui_helpline__push("Press <- or ESC to exit");
407
408 notes = symbol__annotation(sym);
409
410 list_for_each_entry(pos, &notes->src->source, node) {
411 struct objdump_line_rb_node *rbpos;
412 size_t line_len = strlen(pos->line);
413
414 if (browser.b.width < line_len)
415 browser.b.width = line_len;
416 rbpos = objdump_line__rb(pos);
417 rbpos->idx = browser.nr_entries++;
418 if (pos->offset != -1)
419 rbpos->idx_asm = browser.nr_asm_entries++;
420 else
421 rbpos->idx_asm = -1;
422 }
423
424 browser.b.nr_entries = browser.nr_entries;
425 browser.b.entries = &notes->src->source,
426 browser.b.width += 18; /* Percentage */
427 ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
428 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
429 list_del(&pos->node);
430 objdump_line__free(pos);
431 }
432 return ret;
433}
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
deleted file mode 100644
index 2f83e5dc9967..000000000000
--- a/tools/perf/util/ui/browsers/hists.c
+++ /dev/null
@@ -1,1341 +0,0 @@
1#include <stdio.h>
2#include "../libslang.h"
3#include <stdlib.h>
4#include <string.h>
5#include <newt.h>
6#include <linux/rbtree.h>
7
8#include "../../evsel.h"
9#include "../../evlist.h"
10#include "../../hist.h"
11#include "../../pstack.h"
12#include "../../sort.h"
13#include "../../util.h"
14
15#include "../browser.h"
16#include "../helpline.h"
17#include "../util.h"
18#include "../ui.h"
19#include "map.h"
20
21struct hist_browser {
22 struct ui_browser b;
23 struct hists *hists;
24 struct hist_entry *he_selection;
25 struct map_symbol *selection;
26 bool has_symbols;
27};
28
29static int hists__browser_title(struct hists *self, char *bf, size_t size,
30 const char *ev_name);
31
32static void hist_browser__refresh_dimensions(struct hist_browser *self)
33{
34 /* 3 == +/- toggle symbol before actual hist_entry rendering */
35 self->b.width = 3 + (hists__sort_list_width(self->hists) +
36 sizeof("[k]"));
37}
38
39static void hist_browser__reset(struct hist_browser *self)
40{
41 self->b.nr_entries = self->hists->nr_entries;
42 hist_browser__refresh_dimensions(self);
43 ui_browser__reset_index(&self->b);
44}
45
46static char tree__folded_sign(bool unfolded)
47{
48 return unfolded ? '-' : '+';
49}
50
51static char map_symbol__folded(const struct map_symbol *self)
52{
53 return self->has_children ? tree__folded_sign(self->unfolded) : ' ';
54}
55
56static char hist_entry__folded(const struct hist_entry *self)
57{
58 return map_symbol__folded(&self->ms);
59}
60
61static char callchain_list__folded(const struct callchain_list *self)
62{
63 return map_symbol__folded(&self->ms);
64}
65
66static void map_symbol__set_folding(struct map_symbol *self, bool unfold)
67{
68 self->unfolded = unfold ? self->has_children : false;
69}
70
71static int callchain_node__count_rows_rb_tree(struct callchain_node *self)
72{
73 int n = 0;
74 struct rb_node *nd;
75
76 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
77 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
78 struct callchain_list *chain;
79 char folded_sign = ' '; /* No children */
80
81 list_for_each_entry(chain, &child->val, list) {
82 ++n;
83 /* We need this because we may not have children */
84 folded_sign = callchain_list__folded(chain);
85 if (folded_sign == '+')
86 break;
87 }
88
89 if (folded_sign == '-') /* Have children and they're unfolded */
90 n += callchain_node__count_rows_rb_tree(child);
91 }
92
93 return n;
94}
95
96static int callchain_node__count_rows(struct callchain_node *node)
97{
98 struct callchain_list *chain;
99 bool unfolded = false;
100 int n = 0;
101
102 list_for_each_entry(chain, &node->val, list) {
103 ++n;
104 unfolded = chain->ms.unfolded;
105 }
106
107 if (unfolded)
108 n += callchain_node__count_rows_rb_tree(node);
109
110 return n;
111}
112
113static int callchain__count_rows(struct rb_root *chain)
114{
115 struct rb_node *nd;
116 int n = 0;
117
118 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
119 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
120 n += callchain_node__count_rows(node);
121 }
122
123 return n;
124}
125
126static bool map_symbol__toggle_fold(struct map_symbol *self)
127{
128 if (!self)
129 return false;
130
131 if (!self->has_children)
132 return false;
133
134 self->unfolded = !self->unfolded;
135 return true;
136}
137
138static void callchain_node__init_have_children_rb_tree(struct callchain_node *self)
139{
140 struct rb_node *nd = rb_first(&self->rb_root);
141
142 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
143 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
144 struct callchain_list *chain;
145 bool first = true;
146
147 list_for_each_entry(chain, &child->val, list) {
148 if (first) {
149 first = false;
150 chain->ms.has_children = chain->list.next != &child->val ||
151 !RB_EMPTY_ROOT(&child->rb_root);
152 } else
153 chain->ms.has_children = chain->list.next == &child->val &&
154 !RB_EMPTY_ROOT(&child->rb_root);
155 }
156
157 callchain_node__init_have_children_rb_tree(child);
158 }
159}
160
161static void callchain_node__init_have_children(struct callchain_node *self)
162{
163 struct callchain_list *chain;
164
165 list_for_each_entry(chain, &self->val, list)
166 chain->ms.has_children = !RB_EMPTY_ROOT(&self->rb_root);
167
168 callchain_node__init_have_children_rb_tree(self);
169}
170
171static void callchain__init_have_children(struct rb_root *self)
172{
173 struct rb_node *nd;
174
175 for (nd = rb_first(self); nd; nd = rb_next(nd)) {
176 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
177 callchain_node__init_have_children(node);
178 }
179}
180
181static void hist_entry__init_have_children(struct hist_entry *self)
182{
183 if (!self->init_have_children) {
184 self->ms.has_children = !RB_EMPTY_ROOT(&self->sorted_chain);
185 callchain__init_have_children(&self->sorted_chain);
186 self->init_have_children = true;
187 }
188}
189
190static bool hist_browser__toggle_fold(struct hist_browser *self)
191{
192 if (map_symbol__toggle_fold(self->selection)) {
193 struct hist_entry *he = self->he_selection;
194
195 hist_entry__init_have_children(he);
196 self->hists->nr_entries -= he->nr_rows;
197
198 if (he->ms.unfolded)
199 he->nr_rows = callchain__count_rows(&he->sorted_chain);
200 else
201 he->nr_rows = 0;
202 self->hists->nr_entries += he->nr_rows;
203 self->b.nr_entries = self->hists->nr_entries;
204
205 return true;
206 }
207
208 /* If it doesn't have children, no toggling performed */
209 return false;
210}
211
212static int callchain_node__set_folding_rb_tree(struct callchain_node *self, bool unfold)
213{
214 int n = 0;
215 struct rb_node *nd;
216
217 for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
218 struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
219 struct callchain_list *chain;
220 bool has_children = false;
221
222 list_for_each_entry(chain, &child->val, list) {
223 ++n;
224 map_symbol__set_folding(&chain->ms, unfold);
225 has_children = chain->ms.has_children;
226 }
227
228 if (has_children)
229 n += callchain_node__set_folding_rb_tree(child, unfold);
230 }
231
232 return n;
233}
234
235static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
236{
237 struct callchain_list *chain;
238 bool has_children = false;
239 int n = 0;
240
241 list_for_each_entry(chain, &node->val, list) {
242 ++n;
243 map_symbol__set_folding(&chain->ms, unfold);
244 has_children = chain->ms.has_children;
245 }
246
247 if (has_children)
248 n += callchain_node__set_folding_rb_tree(node, unfold);
249
250 return n;
251}
252
253static int callchain__set_folding(struct rb_root *chain, bool unfold)
254{
255 struct rb_node *nd;
256 int n = 0;
257
258 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
259 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
260 n += callchain_node__set_folding(node, unfold);
261 }
262
263 return n;
264}
265
266static void hist_entry__set_folding(struct hist_entry *self, bool unfold)
267{
268 hist_entry__init_have_children(self);
269 map_symbol__set_folding(&self->ms, unfold);
270
271 if (self->ms.has_children) {
272 int n = callchain__set_folding(&self->sorted_chain, unfold);
273 self->nr_rows = unfold ? n : 0;
274 } else
275 self->nr_rows = 0;
276}
277
278static void hists__set_folding(struct hists *self, bool unfold)
279{
280 struct rb_node *nd;
281
282 self->nr_entries = 0;
283
284 for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
285 struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
286 hist_entry__set_folding(he, unfold);
287 self->nr_entries += 1 + he->nr_rows;
288 }
289}
290
291static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
292{
293 hists__set_folding(self->hists, unfold);
294 self->b.nr_entries = self->hists->nr_entries;
295 /* Go to the start, we may be way after valid entries after a collapse */
296 ui_browser__reset_index(&self->b);
297}
298
299static void ui_browser__warn_lost_events(struct ui_browser *browser)
300{
301 ui_browser__warning(browser, 4,
302 "Events are being lost, check IO/CPU overload!\n\n"
303 "You may want to run 'perf' using a RT scheduler policy:\n\n"
304 " perf top -r 80\n\n"
305 "Or reduce the sampling frequency.");
306}
307
308static int hist_browser__run(struct hist_browser *self, const char *ev_name,
309 void(*timer)(void *arg), void *arg, int delay_secs)
310{
311 int key;
312 char title[160];
313
314 self->b.entries = &self->hists->entries;
315 self->b.nr_entries = self->hists->nr_entries;
316
317 hist_browser__refresh_dimensions(self);
318 hists__browser_title(self->hists, title, sizeof(title), ev_name);
319
320 if (ui_browser__show(&self->b, title,
321 "Press '?' for help on key bindings") < 0)
322 return -1;
323
324 while (1) {
325 key = ui_browser__run(&self->b, delay_secs);
326
327 switch (key) {
328 case K_TIMER:
329 timer(arg);
330 ui_browser__update_nr_entries(&self->b, self->hists->nr_entries);
331
332 if (self->hists->stats.nr_lost_warned !=
333 self->hists->stats.nr_events[PERF_RECORD_LOST]) {
334 self->hists->stats.nr_lost_warned =
335 self->hists->stats.nr_events[PERF_RECORD_LOST];
336 ui_browser__warn_lost_events(&self->b);
337 }
338
339 hists__browser_title(self->hists, title, sizeof(title), ev_name);
340 ui_browser__show_title(&self->b, title);
341 continue;
342 case 'D': { /* Debug */
343 static int seq;
344 struct hist_entry *h = rb_entry(self->b.top,
345 struct hist_entry, rb_node);
346 ui_helpline__pop();
347 ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
348 seq++, self->b.nr_entries,
349 self->hists->nr_entries,
350 self->b.height,
351 self->b.index,
352 self->b.top_idx,
353 h->row_offset, h->nr_rows);
354 }
355 break;
356 case 'C':
357 /* Collapse the whole world. */
358 hist_browser__set_folding(self, false);
359 break;
360 case 'E':
361 /* Expand the whole world. */
362 hist_browser__set_folding(self, true);
363 break;
364 case K_ENTER:
365 if (hist_browser__toggle_fold(self))
366 break;
367 /* fall thru */
368 default:
369 goto out;
370 }
371 }
372out:
373 ui_browser__hide(&self->b);
374 return key;
375}
376
377static char *callchain_list__sym_name(struct callchain_list *self,
378 char *bf, size_t bfsize)
379{
380 if (self->ms.sym)
381 return self->ms.sym->name;
382
383 snprintf(bf, bfsize, "%#" PRIx64, self->ip);
384 return bf;
385}
386
387#define LEVEL_OFFSET_STEP 3
388
389static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
390 struct callchain_node *chain_node,
391 u64 total, int level,
392 unsigned short row,
393 off_t *row_offset,
394 bool *is_current_entry)
395{
396 struct rb_node *node;
397 int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
398 u64 new_total, remaining;
399
400 if (callchain_param.mode == CHAIN_GRAPH_REL)
401 new_total = chain_node->children_hit;
402 else
403 new_total = total;
404
405 remaining = new_total;
406 node = rb_first(&chain_node->rb_root);
407 while (node) {
408 struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
409 struct rb_node *next = rb_next(node);
410 u64 cumul = callchain_cumul_hits(child);
411 struct callchain_list *chain;
412 char folded_sign = ' ';
413 int first = true;
414 int extra_offset = 0;
415
416 remaining -= cumul;
417
418 list_for_each_entry(chain, &child->val, list) {
419 char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
420 const char *str;
421 int color;
422 bool was_first = first;
423
424 if (first)
425 first = false;
426 else
427 extra_offset = LEVEL_OFFSET_STEP;
428
429 folded_sign = callchain_list__folded(chain);
430 if (*row_offset != 0) {
431 --*row_offset;
432 goto do_next;
433 }
434
435 alloc_str = NULL;
436 str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
437 if (was_first) {
438 double percent = cumul * 100.0 / new_total;
439
440 if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
441 str = "Not enough memory!";
442 else
443 str = alloc_str;
444 }
445
446 color = HE_COLORSET_NORMAL;
447 width = self->b.width - (offset + extra_offset + 2);
448 if (ui_browser__is_current_entry(&self->b, row)) {
449 self->selection = &chain->ms;
450 color = HE_COLORSET_SELECTED;
451 *is_current_entry = true;
452 }
453
454 ui_browser__set_color(&self->b, color);
455 ui_browser__gotorc(&self->b, row, 0);
456 slsmg_write_nstring(" ", offset + extra_offset);
457 slsmg_printf("%c ", folded_sign);
458 slsmg_write_nstring(str, width);
459 free(alloc_str);
460
461 if (++row == self->b.height)
462 goto out;
463do_next:
464 if (folded_sign == '+')
465 break;
466 }
467
468 if (folded_sign == '-') {
469 const int new_level = level + (extra_offset ? 2 : 1);
470 row += hist_browser__show_callchain_node_rb_tree(self, child, new_total,
471 new_level, row, row_offset,
472 is_current_entry);
473 }
474 if (row == self->b.height)
475 goto out;
476 node = next;
477 }
478out:
479 return row - first_row;
480}
481
482static int hist_browser__show_callchain_node(struct hist_browser *self,
483 struct callchain_node *node,
484 int level, unsigned short row,
485 off_t *row_offset,
486 bool *is_current_entry)
487{
488 struct callchain_list *chain;
489 int first_row = row,
490 offset = level * LEVEL_OFFSET_STEP,
491 width = self->b.width - offset;
492 char folded_sign = ' ';
493
494 list_for_each_entry(chain, &node->val, list) {
495 char ipstr[BITS_PER_LONG / 4 + 1], *s;
496 int color;
497
498 folded_sign = callchain_list__folded(chain);
499
500 if (*row_offset != 0) {
501 --*row_offset;
502 continue;
503 }
504
505 color = HE_COLORSET_NORMAL;
506 if (ui_browser__is_current_entry(&self->b, row)) {
507 self->selection = &chain->ms;
508 color = HE_COLORSET_SELECTED;
509 *is_current_entry = true;
510 }
511
512 s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
513 ui_browser__gotorc(&self->b, row, 0);
514 ui_browser__set_color(&self->b, color);
515 slsmg_write_nstring(" ", offset);
516 slsmg_printf("%c ", folded_sign);
517 slsmg_write_nstring(s, width - 2);
518
519 if (++row == self->b.height)
520 goto out;
521 }
522
523 if (folded_sign == '-')
524 row += hist_browser__show_callchain_node_rb_tree(self, node,
525 self->hists->stats.total_period,
526 level + 1, row,
527 row_offset,
528 is_current_entry);
529out:
530 return row - first_row;
531}
532
533static int hist_browser__show_callchain(struct hist_browser *self,
534 struct rb_root *chain,
535 int level, unsigned short row,
536 off_t *row_offset,
537 bool *is_current_entry)
538{
539 struct rb_node *nd;
540 int first_row = row;
541
542 for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
543 struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
544
545 row += hist_browser__show_callchain_node(self, node, level,
546 row, row_offset,
547 is_current_entry);
548 if (row == self->b.height)
549 break;
550 }
551
552 return row - first_row;
553}
554
555static int hist_browser__show_entry(struct hist_browser *self,
556 struct hist_entry *entry,
557 unsigned short row)
558{
559 char s[256];
560 double percent;
561 int printed = 0;
562 int width = self->b.width - 6; /* The percentage */
563 char folded_sign = ' ';
564 bool current_entry = ui_browser__is_current_entry(&self->b, row);
565 off_t row_offset = entry->row_offset;
566
567 if (current_entry) {
568 self->he_selection = entry;
569 self->selection = &entry->ms;
570 }
571
572 if (symbol_conf.use_callchain) {
573 hist_entry__init_have_children(entry);
574 folded_sign = hist_entry__folded(entry);
575 }
576
577 if (row_offset == 0) {
578 hist_entry__snprintf(entry, s, sizeof(s), self->hists);
579 percent = (entry->period * 100.0) / self->hists->stats.total_period;
580
581 ui_browser__set_percent_color(&self->b, percent, current_entry);
582 ui_browser__gotorc(&self->b, row, 0);
583 if (symbol_conf.use_callchain) {
584 slsmg_printf("%c ", folded_sign);
585 width -= 2;
586 }
587
588 slsmg_printf(" %5.2f%%", percent);
589
590 /* The scroll bar isn't being used */
591 if (!self->b.navkeypressed)
592 width += 1;
593
594 if (!current_entry || !self->b.navkeypressed)
595 ui_browser__set_color(&self->b, HE_COLORSET_NORMAL);
596
597 if (symbol_conf.show_nr_samples) {
598 slsmg_printf(" %11u", entry->nr_events);
599 width -= 12;
600 }
601
602 if (symbol_conf.show_total_period) {
603 slsmg_printf(" %12" PRIu64, entry->period);
604 width -= 13;
605 }
606
607 slsmg_write_nstring(s, width);
608 ++row;
609 ++printed;
610 } else
611 --row_offset;
612
613 if (folded_sign == '-' && row != self->b.height) {
614 printed += hist_browser__show_callchain(self, &entry->sorted_chain,
615 1, row, &row_offset,
616 &current_entry);
617 if (current_entry)
618 self->he_selection = entry;
619 }
620
621 return printed;
622}
623
624static void ui_browser__hists_init_top(struct ui_browser *browser)
625{
626 if (browser->top == NULL) {
627 struct hist_browser *hb;
628
629 hb = container_of(browser, struct hist_browser, b);
630 browser->top = rb_first(&hb->hists->entries);
631 }
632}
633
634static unsigned int hist_browser__refresh(struct ui_browser *self)
635{
636 unsigned row = 0;
637 struct rb_node *nd;
638 struct hist_browser *hb = container_of(self, struct hist_browser, b);
639
640 ui_browser__hists_init_top(self);
641
642 for (nd = self->top; nd; nd = rb_next(nd)) {
643 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
644
645 if (h->filtered)
646 continue;
647
648 row += hist_browser__show_entry(hb, h, row);
649 if (row == self->height)
650 break;
651 }
652
653 return row;
654}
655
656static struct rb_node *hists__filter_entries(struct rb_node *nd)
657{
658 while (nd != NULL) {
659 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
660 if (!h->filtered)
661 return nd;
662
663 nd = rb_next(nd);
664 }
665
666 return NULL;
667}
668
669static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
670{
671 while (nd != NULL) {
672 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
673 if (!h->filtered)
674 return nd;
675
676 nd = rb_prev(nd);
677 }
678
679 return NULL;
680}
681
682static void ui_browser__hists_seek(struct ui_browser *self,
683 off_t offset, int whence)
684{
685 struct hist_entry *h;
686 struct rb_node *nd;
687 bool first = true;
688
689 if (self->nr_entries == 0)
690 return;
691
692 ui_browser__hists_init_top(self);
693
694 switch (whence) {
695 case SEEK_SET:
696 nd = hists__filter_entries(rb_first(self->entries));
697 break;
698 case SEEK_CUR:
699 nd = self->top;
700 goto do_offset;
701 case SEEK_END:
702 nd = hists__filter_prev_entries(rb_last(self->entries));
703 first = false;
704 break;
705 default:
706 return;
707 }
708
709 /*
710 * Moves not relative to the first visible entry invalidates its
711 * row_offset:
712 */
713 h = rb_entry(self->top, struct hist_entry, rb_node);
714 h->row_offset = 0;
715
716 /*
717 * Here we have to check if nd is expanded (+), if it is we can't go
718 * the next top level hist_entry, instead we must compute an offset of
719 * what _not_ to show and not change the first visible entry.
720 *
721 * This offset increments when we are going from top to bottom and
722 * decreases when we're going from bottom to top.
723 *
724 * As we don't have backpointers to the top level in the callchains
725 * structure, we need to always print the whole hist_entry callchain,
726 * skipping the first ones that are before the first visible entry
727 * and stop when we printed enough lines to fill the screen.
728 */
729do_offset:
730 if (offset > 0) {
731 do {
732 h = rb_entry(nd, struct hist_entry, rb_node);
733 if (h->ms.unfolded) {
734 u16 remaining = h->nr_rows - h->row_offset;
735 if (offset > remaining) {
736 offset -= remaining;
737 h->row_offset = 0;
738 } else {
739 h->row_offset += offset;
740 offset = 0;
741 self->top = nd;
742 break;
743 }
744 }
745 nd = hists__filter_entries(rb_next(nd));
746 if (nd == NULL)
747 break;
748 --offset;
749 self->top = nd;
750 } while (offset != 0);
751 } else if (offset < 0) {
752 while (1) {
753 h = rb_entry(nd, struct hist_entry, rb_node);
754 if (h->ms.unfolded) {
755 if (first) {
756 if (-offset > h->row_offset) {
757 offset += h->row_offset;
758 h->row_offset = 0;
759 } else {
760 h->row_offset += offset;
761 offset = 0;
762 self->top = nd;
763 break;
764 }
765 } else {
766 if (-offset > h->nr_rows) {
767 offset += h->nr_rows;
768 h->row_offset = 0;
769 } else {
770 h->row_offset = h->nr_rows + offset;
771 offset = 0;
772 self->top = nd;
773 break;
774 }
775 }
776 }
777
778 nd = hists__filter_prev_entries(rb_prev(nd));
779 if (nd == NULL)
780 break;
781 ++offset;
782 self->top = nd;
783 if (offset == 0) {
784 /*
785 * Last unfiltered hist_entry, check if it is
786 * unfolded, if it is then we should have
787 * row_offset at its last entry.
788 */
789 h = rb_entry(nd, struct hist_entry, rb_node);
790 if (h->ms.unfolded)
791 h->row_offset = h->nr_rows;
792 break;
793 }
794 first = false;
795 }
796 } else {
797 self->top = nd;
798 h = rb_entry(nd, struct hist_entry, rb_node);
799 h->row_offset = 0;
800 }
801}
802
803static struct hist_browser *hist_browser__new(struct hists *hists)
804{
805 struct hist_browser *self = zalloc(sizeof(*self));
806
807 if (self) {
808 self->hists = hists;
809 self->b.refresh = hist_browser__refresh;
810 self->b.seek = ui_browser__hists_seek;
811 self->b.use_navkeypressed = true;
812 if (sort__branch_mode == 1)
813 self->has_symbols = sort_sym_from.list.next != NULL;
814 else
815 self->has_symbols = sort_sym.list.next != NULL;
816 }
817
818 return self;
819}
820
821static void hist_browser__delete(struct hist_browser *self)
822{
823 free(self);
824}
825
826static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self)
827{
828 return self->he_selection;
829}
830
831static struct thread *hist_browser__selected_thread(struct hist_browser *self)
832{
833 return self->he_selection->thread;
834}
835
836static int hists__browser_title(struct hists *self, char *bf, size_t size,
837 const char *ev_name)
838{
839 char unit;
840 int printed;
841 const struct dso *dso = self->dso_filter;
842 const struct thread *thread = self->thread_filter;
843 unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
844
845 nr_events = convert_unit(nr_events, &unit);
846 printed = scnprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
847
848 if (self->uid_filter_str)
849 printed += snprintf(bf + printed, size - printed,
850 ", UID: %s", self->uid_filter_str);
851 if (thread)
852 printed += scnprintf(bf + printed, size - printed,
853 ", Thread: %s(%d)",
854 (thread->comm_set ? thread->comm : ""),
855 thread->pid);
856 if (dso)
857 printed += scnprintf(bf + printed, size - printed,
858 ", DSO: %s", dso->short_name);
859 return printed;
860}
861
862static inline void free_popup_options(char **options, int n)
863{
864 int i;
865
866 for (i = 0; i < n; ++i) {
867 free(options[i]);
868 options[i] = NULL;
869 }
870}
871
872static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
873 const char *helpline, const char *ev_name,
874 bool left_exits,
875 void(*timer)(void *arg), void *arg,
876 int delay_secs)
877{
878 struct hists *self = &evsel->hists;
879 struct hist_browser *browser = hist_browser__new(self);
880 struct branch_info *bi;
881 struct pstack *fstack;
882 char *options[16];
883 int nr_options = 0;
884 int key = -1;
885 char buf[64];
886
887 if (browser == NULL)
888 return -1;
889
890 fstack = pstack__new(2);
891 if (fstack == NULL)
892 goto out;
893
894 ui_helpline__push(helpline);
895
896 memset(options, 0, sizeof(options));
897
898 while (1) {
899 const struct thread *thread = NULL;
900 const struct dso *dso = NULL;
901 int choice = 0,
902 annotate = -2, zoom_dso = -2, zoom_thread = -2,
903 annotate_f = -2, annotate_t = -2, browse_map = -2;
904
905 nr_options = 0;
906
907 key = hist_browser__run(browser, ev_name, timer, arg, delay_secs);
908
909 if (browser->he_selection != NULL) {
910 thread = hist_browser__selected_thread(browser);
911 dso = browser->selection->map ? browser->selection->map->dso : NULL;
912 }
913 switch (key) {
914 case K_TAB:
915 case K_UNTAB:
916 if (nr_events == 1)
917 continue;
918 /*
919 * Exit the browser, let hists__browser_tree
920 * go to the next or previous
921 */
922 goto out_free_stack;
923 case 'a':
924 if (!browser->has_symbols) {
925 ui_browser__warning(&browser->b, delay_secs * 2,
926 "Annotation is only available for symbolic views, "
927 "include \"sym*\" in --sort to use it.");
928 continue;
929 }
930
931 if (browser->selection == NULL ||
932 browser->selection->sym == NULL ||
933 browser->selection->map->dso->annotate_warned)
934 continue;
935 goto do_annotate;
936 case 'd':
937 goto zoom_dso;
938 case 't':
939 goto zoom_thread;
940 case 's':
941 if (ui_browser__input_window("Symbol to show",
942 "Please enter the name of symbol you want to see",
943 buf, "ENTER: OK, ESC: Cancel",
944 delay_secs * 2) == K_ENTER) {
945 self->symbol_filter_str = *buf ? buf : NULL;
946 hists__filter_by_symbol(self);
947 hist_browser__reset(browser);
948 }
949 continue;
950 case K_F1:
951 case 'h':
952 case '?':
953 ui_browser__help_window(&browser->b,
954 "h/?/F1 Show this window\n"
955 "UP/DOWN/PGUP\n"
956 "PGDN/SPACE Navigate\n"
957 "q/ESC/CTRL+C Exit browser\n\n"
958 "For multiple event sessions:\n\n"
959 "TAB/UNTAB Switch events\n\n"
960 "For symbolic views (--sort has sym):\n\n"
961 "-> Zoom into DSO/Threads & Annotate current symbol\n"
962 "<- Zoom out\n"
963 "a Annotate current symbol\n"
964 "C Collapse all callchains\n"
965 "E Expand all callchains\n"
966 "d Zoom into current DSO\n"
967 "t Zoom into current Thread\n"
968 "s Filter symbol by name");
969 continue;
970 case K_ENTER:
971 case K_RIGHT:
972 /* menu */
973 break;
974 case K_LEFT: {
975 const void *top;
976
977 if (pstack__empty(fstack)) {
978 /*
979 * Go back to the perf_evsel_menu__run or other user
980 */
981 if (left_exits)
982 goto out_free_stack;
983 continue;
984 }
985 top = pstack__pop(fstack);
986 if (top == &browser->hists->dso_filter)
987 goto zoom_out_dso;
988 if (top == &browser->hists->thread_filter)
989 goto zoom_out_thread;
990 continue;
991 }
992 case K_ESC:
993 if (!left_exits &&
994 !ui_browser__dialog_yesno(&browser->b,
995 "Do you really want to exit?"))
996 continue;
997 /* Fall thru */
998 case 'q':
999 case CTRL('c'):
1000 goto out_free_stack;
1001 default:
1002 continue;
1003 }
1004
1005 if (!browser->has_symbols)
1006 goto add_exit_option;
1007
1008 if (sort__branch_mode == 1) {
1009 bi = browser->he_selection->branch_info;
1010 if (browser->selection != NULL &&
1011 bi &&
1012 bi->from.sym != NULL &&
1013 !bi->from.map->dso->annotate_warned &&
1014 asprintf(&options[nr_options], "Annotate %s",
1015 bi->from.sym->name) > 0)
1016 annotate_f = nr_options++;
1017
1018 if (browser->selection != NULL &&
1019 bi &&
1020 bi->to.sym != NULL &&
1021 !bi->to.map->dso->annotate_warned &&
1022 (bi->to.sym != bi->from.sym ||
1023 bi->to.map->dso != bi->from.map->dso) &&
1024 asprintf(&options[nr_options], "Annotate %s",
1025 bi->to.sym->name) > 0)
1026 annotate_t = nr_options++;
1027 } else {
1028
1029 if (browser->selection != NULL &&
1030 browser->selection->sym != NULL &&
1031 !browser->selection->map->dso->annotate_warned &&
1032 asprintf(&options[nr_options], "Annotate %s",
1033 browser->selection->sym->name) > 0)
1034 annotate = nr_options++;
1035 }
1036
1037 if (thread != NULL &&
1038 asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
1039 (browser->hists->thread_filter ? "out of" : "into"),
1040 (thread->comm_set ? thread->comm : ""),
1041 thread->pid) > 0)
1042 zoom_thread = nr_options++;
1043
1044 if (dso != NULL &&
1045 asprintf(&options[nr_options], "Zoom %s %s DSO",
1046 (browser->hists->dso_filter ? "out of" : "into"),
1047 (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
1048 zoom_dso = nr_options++;
1049
1050 if (browser->selection != NULL &&
1051 browser->selection->map != NULL &&
1052 asprintf(&options[nr_options], "Browse map details") > 0)
1053 browse_map = nr_options++;
1054add_exit_option:
1055 options[nr_options++] = (char *)"Exit";
1056retry_popup_menu:
1057 choice = ui__popup_menu(nr_options, options);
1058
1059 if (choice == nr_options - 1)
1060 break;
1061
1062 if (choice == -1) {
1063 free_popup_options(options, nr_options - 1);
1064 continue;
1065 }
1066
1067 if (choice == annotate || choice == annotate_t || choice == annotate_f) {
1068 struct hist_entry *he;
1069 int err;
1070do_annotate:
1071 he = hist_browser__selected_entry(browser);
1072 if (he == NULL)
1073 continue;
1074
1075 /*
1076 * we stash the branch_info symbol + map into the
1077 * the ms so we don't have to rewrite all the annotation
1078 * code to use branch_info.
1079 * in branch mode, the ms struct is not used
1080 */
1081 if (choice == annotate_f) {
1082 he->ms.sym = he->branch_info->from.sym;
1083 he->ms.map = he->branch_info->from.map;
1084 } else if (choice == annotate_t) {
1085 he->ms.sym = he->branch_info->to.sym;
1086 he->ms.map = he->branch_info->to.map;
1087 }
1088
1089 /*
1090 * Don't let this be freed, say, by hists__decay_entry.
1091 */
1092 he->used = true;
1093 err = hist_entry__tui_annotate(he, evsel->idx,
1094 timer, arg, delay_secs);
1095 he->used = false;
1096 /*
1097 * offer option to annotate the other branch source or target
1098 * (if they exists) when returning from annotate
1099 */
1100 if ((err == 'q' || err == CTRL('c'))
1101 && annotate_t != -2 && annotate_f != -2)
1102 goto retry_popup_menu;
1103
1104 ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
1105 if (err)
1106 ui_browser__handle_resize(&browser->b);
1107
1108 } else if (choice == browse_map)
1109 map__browse(browser->selection->map);
1110 else if (choice == zoom_dso) {
1111zoom_dso:
1112 if (browser->hists->dso_filter) {
1113 pstack__remove(fstack, &browser->hists->dso_filter);
1114zoom_out_dso:
1115 ui_helpline__pop();
1116 browser->hists->dso_filter = NULL;
1117 sort_dso.elide = false;
1118 } else {
1119 if (dso == NULL)
1120 continue;
1121 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
1122 dso->kernel ? "the Kernel" : dso->short_name);
1123 browser->hists->dso_filter = dso;
1124 sort_dso.elide = true;
1125 pstack__push(fstack, &browser->hists->dso_filter);
1126 }
1127 hists__filter_by_dso(self);
1128 hist_browser__reset(browser);
1129 } else if (choice == zoom_thread) {
1130zoom_thread:
1131 if (browser->hists->thread_filter) {
1132 pstack__remove(fstack, &browser->hists->thread_filter);
1133zoom_out_thread:
1134 ui_helpline__pop();
1135 browser->hists->thread_filter = NULL;
1136 sort_thread.elide = false;
1137 } else {
1138 ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
1139 thread->comm_set ? thread->comm : "",
1140 thread->pid);
1141 browser->hists->thread_filter = thread;
1142 sort_thread.elide = true;
1143 pstack__push(fstack, &browser->hists->thread_filter);
1144 }
1145 hists__filter_by_thread(self);
1146 hist_browser__reset(browser);
1147 }
1148 }
1149out_free_stack:
1150 pstack__delete(fstack);
1151out:
1152 hist_browser__delete(browser);
1153 free_popup_options(options, nr_options - 1);
1154 return key;
1155}
1156
1157struct perf_evsel_menu {
1158 struct ui_browser b;
1159 struct perf_evsel *selection;
1160 bool lost_events, lost_events_warned;
1161};
1162
1163static void perf_evsel_menu__write(struct ui_browser *browser,
1164 void *entry, int row)
1165{
1166 struct perf_evsel_menu *menu = container_of(browser,
1167 struct perf_evsel_menu, b);
1168 struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
1169 bool current_entry = ui_browser__is_current_entry(browser, row);
1170 unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
1171 const char *ev_name = event_name(evsel);
1172 char bf[256], unit;
1173 const char *warn = " ";
1174 size_t printed;
1175
1176 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
1177 HE_COLORSET_NORMAL);
1178
1179 nr_events = convert_unit(nr_events, &unit);
1180 printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
1181 unit, unit == ' ' ? "" : " ", ev_name);
1182 slsmg_printf("%s", bf);
1183
1184 nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
1185 if (nr_events != 0) {
1186 menu->lost_events = true;
1187 if (!current_entry)
1188 ui_browser__set_color(browser, HE_COLORSET_TOP);
1189 nr_events = convert_unit(nr_events, &unit);
1190 printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
1191 nr_events, unit, unit == ' ' ? "" : " ");
1192 warn = bf;
1193 }
1194
1195 slsmg_write_nstring(warn, browser->width - printed);
1196
1197 if (current_entry)
1198 menu->selection = evsel;
1199}
1200
1201static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
1202 int nr_events, const char *help,
1203 void(*timer)(void *arg), void *arg, int delay_secs)
1204{
1205 struct perf_evlist *evlist = menu->b.priv;
1206 struct perf_evsel *pos;
1207 const char *ev_name, *title = "Available samples";
1208 int key;
1209
1210 if (ui_browser__show(&menu->b, title,
1211 "ESC: exit, ENTER|->: Browse histograms") < 0)
1212 return -1;
1213
1214 while (1) {
1215 key = ui_browser__run(&menu->b, delay_secs);
1216
1217 switch (key) {
1218 case K_TIMER:
1219 timer(arg);
1220
1221 if (!menu->lost_events_warned && menu->lost_events) {
1222 ui_browser__warn_lost_events(&menu->b);
1223 menu->lost_events_warned = true;
1224 }
1225 continue;
1226 case K_RIGHT:
1227 case K_ENTER:
1228 if (!menu->selection)
1229 continue;
1230 pos = menu->selection;
1231browse_hists:
1232 perf_evlist__set_selected(evlist, pos);
1233 /*
1234 * Give the calling tool a chance to populate the non
1235 * default evsel resorted hists tree.
1236 */
1237 if (timer)
1238 timer(arg);
1239 ev_name = event_name(pos);
1240 key = perf_evsel__hists_browse(pos, nr_events, help,
1241 ev_name, true, timer,
1242 arg, delay_secs);
1243 ui_browser__show_title(&menu->b, title);
1244 switch (key) {
1245 case K_TAB:
1246 if (pos->node.next == &evlist->entries)
1247 pos = list_entry(evlist->entries.next, struct perf_evsel, node);
1248 else
1249 pos = list_entry(pos->node.next, struct perf_evsel, node);
1250 goto browse_hists;
1251 case K_UNTAB:
1252 if (pos->node.prev == &evlist->entries)
1253 pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
1254 else
1255 pos = list_entry(pos->node.prev, struct perf_evsel, node);
1256 goto browse_hists;
1257 case K_ESC:
1258 if (!ui_browser__dialog_yesno(&menu->b,
1259 "Do you really want to exit?"))
1260 continue;
1261 /* Fall thru */
1262 case 'q':
1263 case CTRL('c'):
1264 goto out;
1265 default:
1266 continue;
1267 }
1268 case K_LEFT:
1269 continue;
1270 case K_ESC:
1271 if (!ui_browser__dialog_yesno(&menu->b,
1272 "Do you really want to exit?"))
1273 continue;
1274 /* Fall thru */
1275 case 'q':
1276 case CTRL('c'):
1277 goto out;
1278 default:
1279 continue;
1280 }
1281 }
1282
1283out:
1284 ui_browser__hide(&menu->b);
1285 return key;
1286}
1287
1288static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
1289 const char *help,
1290 void(*timer)(void *arg), void *arg,
1291 int delay_secs)
1292{
1293 struct perf_evsel *pos;
1294 struct perf_evsel_menu menu = {
1295 .b = {
1296 .entries = &evlist->entries,
1297 .refresh = ui_browser__list_head_refresh,
1298 .seek = ui_browser__list_head_seek,
1299 .write = perf_evsel_menu__write,
1300 .nr_entries = evlist->nr_entries,
1301 .priv = evlist,
1302 },
1303 };
1304
1305 ui_helpline__push("Press ESC to exit");
1306
1307 list_for_each_entry(pos, &evlist->entries, node) {
1308 const char *ev_name = event_name(pos);
1309 size_t line_len = strlen(ev_name) + 7;
1310
1311 if (menu.b.width < line_len)
1312 menu.b.width = line_len;
1313 /*
1314 * Cache the evsel name, tracepoints have a _high_ cost per
1315 * event_name() call.
1316 */
1317 if (pos->name == NULL)
1318 pos->name = strdup(ev_name);
1319 }
1320
1321 return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
1322 arg, delay_secs);
1323}
1324
1325int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
1326 void(*timer)(void *arg), void *arg,
1327 int delay_secs)
1328{
1329
1330 if (evlist->nr_entries == 1) {
1331 struct perf_evsel *first = list_entry(evlist->entries.next,
1332 struct perf_evsel, node);
1333 const char *ev_name = event_name(first);
1334 return perf_evsel__hists_browse(first, evlist->nr_entries, help,
1335 ev_name, false, timer, arg,
1336 delay_secs);
1337 }
1338
1339 return __perf_evlist__tui_browse_hists(evlist, help,
1340 timer, arg, delay_secs);
1341}
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c
deleted file mode 100644
index eca6575abfd0..000000000000
--- a/tools/perf/util/ui/browsers/map.c
+++ /dev/null
@@ -1,154 +0,0 @@
1#include "../libslang.h"
2#include <elf.h>
3#include <newt.h>
4#include <inttypes.h>
5#include <sys/ttydefaults.h>
6#include <string.h>
7#include <linux/bitops.h>
8#include "../../util.h"
9#include "../../debug.h"
10#include "../../symbol.h"
11#include "../browser.h"
12#include "../helpline.h"
13#include "map.h"
14
15static int ui_entry__read(const char *title, char *bf, size_t size, int width)
16{
17 struct newtExitStruct es;
18 newtComponent form, entry;
19 const char *result;
20 int err = -1;
21
22 newtCenteredWindow(width, 1, title);
23 form = newtForm(NULL, NULL, 0);
24 if (form == NULL)
25 return -1;
26
27 entry = newtEntry(0, 0, "0x", width, &result, NEWT_FLAG_SCROLL);
28 if (entry == NULL)
29 goto out_free_form;
30
31 newtFormAddComponent(form, entry);
32 newtFormAddHotKey(form, NEWT_KEY_ENTER);
33 newtFormAddHotKey(form, NEWT_KEY_ESCAPE);
34 newtFormAddHotKey(form, NEWT_KEY_LEFT);
35 newtFormAddHotKey(form, CTRL('c'));
36 newtFormRun(form, &es);
37
38 if (result != NULL) {
39 strncpy(bf, result, size);
40 err = 0;
41 }
42out_free_form:
43 newtPopWindow();
44 newtFormDestroy(form);
45 return err;
46}
47
48struct map_browser {
49 struct ui_browser b;
50 struct map *map;
51 u8 addrlen;
52};
53
54static void map_browser__write(struct ui_browser *self, void *nd, int row)
55{
56 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
57 struct map_browser *mb = container_of(self, struct map_browser, b);
58 bool current_entry = ui_browser__is_current_entry(self, row);
59 int width;
60
61 ui_browser__set_percent_color(self, 0, current_entry);
62 slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",
63 mb->addrlen, sym->start, mb->addrlen, sym->end,
64 sym->binding == STB_GLOBAL ? 'g' :
65 sym->binding == STB_LOCAL ? 'l' : 'w');
66 width = self->width - ((mb->addrlen * 2) + 4);
67 if (width > 0)
68 slsmg_write_nstring(sym->name, width);
69}
70
71/* FIXME uber-kludgy, see comment on cmd_report... */
72static u32 *symbol__browser_index(struct symbol *self)
73{
74 return ((void *)self) - sizeof(struct rb_node) - sizeof(u32);
75}
76
77static int map_browser__search(struct map_browser *self)
78{
79 char target[512];
80 struct symbol *sym;
81 int err = ui_entry__read("Search by name/addr", target, sizeof(target), 40);
82
83 if (err)
84 return err;
85
86 if (target[0] == '0' && tolower(target[1]) == 'x') {
87 u64 addr = strtoull(target, NULL, 16);
88 sym = map__find_symbol(self->map, addr, NULL);
89 } else
90 sym = map__find_symbol_by_name(self->map, target, NULL);
91
92 if (sym != NULL) {
93 u32 *idx = symbol__browser_index(sym);
94
95 self->b.top = &sym->rb_node;
96 self->b.index = self->b.top_idx = *idx;
97 } else
98 ui_helpline__fpush("%s not found!", target);
99
100 return 0;
101}
102
103static int map_browser__run(struct map_browser *self)
104{
105 int key;
106
107 if (ui_browser__show(&self->b, self->map->dso->long_name,
108 "Press <- or ESC to exit, %s / to search",
109 verbose ? "" : "restart with -v to use") < 0)
110 return -1;
111
112 while (1) {
113 key = ui_browser__run(&self->b, 0);
114
115 if (verbose && key == '/')
116 map_browser__search(self);
117 else
118 break;
119 }
120
121 ui_browser__hide(&self->b);
122 return key;
123}
124
125int map__browse(struct map *self)
126{
127 struct map_browser mb = {
128 .b = {
129 .entries = &self->dso->symbols[self->type],
130 .refresh = ui_browser__rb_tree_refresh,
131 .seek = ui_browser__rb_tree_seek,
132 .write = map_browser__write,
133 },
134 .map = self,
135 };
136 struct rb_node *nd;
137 char tmp[BITS_PER_LONG / 4];
138 u64 maxaddr = 0;
139
140 for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) {
141 struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
142
143 if (maxaddr < pos->end)
144 maxaddr = pos->end;
145 if (verbose) {
146 u32 *idx = symbol__browser_index(pos);
147 *idx = mb.b.nr_entries;
148 }
149 ++mb.b.nr_entries;
150 }
151
152 mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr);
153 return map_browser__run(&mb);
154}
diff --git a/tools/perf/util/ui/browsers/map.h b/tools/perf/util/ui/browsers/map.h
deleted file mode 100644
index df8581a43e17..000000000000
--- a/tools/perf/util/ui/browsers/map.h
+++ /dev/null
@@ -1,6 +0,0 @@
1#ifndef _PERF_UI_MAP_BROWSER_H_
2#define _PERF_UI_MAP_BROWSER_H_ 1
3struct map;
4
5int map__browse(struct map *self);
6#endif /* _PERF_UI_MAP_BROWSER_H_ */
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c
deleted file mode 100644
index 2f950c2641c8..000000000000
--- a/tools/perf/util/ui/helpline.c
+++ /dev/null
@@ -1,79 +0,0 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4
5#include "../debug.h"
6#include "helpline.h"
7#include "ui.h"
8#include "libslang.h"
9
10void ui_helpline__pop(void)
11{
12}
13
14char ui_helpline__current[512];
15
16void ui_helpline__push(const char *msg)
17{
18 const size_t sz = sizeof(ui_helpline__current);
19
20 SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
21 SLsmg_set_color(0);
22 SLsmg_write_nstring((char *)msg, SLtt_Screen_Cols);
23 SLsmg_refresh();
24 strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0';
25}
26
27void ui_helpline__vpush(const char *fmt, va_list ap)
28{
29 char *s;
30
31 if (vasprintf(&s, fmt, ap) < 0)
32 vfprintf(stderr, fmt, ap);
33 else {
34 ui_helpline__push(s);
35 free(s);
36 }
37}
38
39void ui_helpline__fpush(const char *fmt, ...)
40{
41 va_list ap;
42
43 va_start(ap, fmt);
44 ui_helpline__vpush(fmt, ap);
45 va_end(ap);
46}
47
48void ui_helpline__puts(const char *msg)
49{
50 ui_helpline__pop();
51 ui_helpline__push(msg);
52}
53
54void ui_helpline__init(void)
55{
56 ui_helpline__puts(" ");
57}
58
59char ui_helpline__last_msg[1024];
60
61int ui_helpline__show_help(const char *format, va_list ap)
62{
63 int ret;
64 static int backlog;
65
66 pthread_mutex_lock(&ui__lock);
67 ret = vscnprintf(ui_helpline__last_msg + backlog,
68 sizeof(ui_helpline__last_msg) - backlog, format, ap);
69 backlog += ret;
70
71 if (ui_helpline__last_msg[backlog - 1] == '\n') {
72 ui_helpline__puts(ui_helpline__last_msg);
73 SLsmg_refresh();
74 backlog = 0;
75 }
76 pthread_mutex_unlock(&ui__lock);
77
78 return ret;
79}
diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/util/ui/helpline.h
deleted file mode 100644
index 7bab6b34e35e..000000000000
--- a/tools/perf/util/ui/helpline.h
+++ /dev/null
@@ -1,16 +0,0 @@
1#ifndef _PERF_UI_HELPLINE_H_
2#define _PERF_UI_HELPLINE_H_ 1
3
4#include <stdio.h>
5#include <stdarg.h>
6
7void ui_helpline__init(void);
8void ui_helpline__pop(void);
9void ui_helpline__push(const char *msg);
10void ui_helpline__vpush(const char *fmt, va_list ap);
11void ui_helpline__fpush(const char *fmt, ...);
12void ui_helpline__puts(const char *msg);
13
14extern char ui_helpline__current[];
15
16#endif /* _PERF_UI_HELPLINE_H_ */
diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/util/ui/keysyms.h
deleted file mode 100644
index 809eca5707fa..000000000000
--- a/tools/perf/util/ui/keysyms.h
+++ /dev/null
@@ -1,27 +0,0 @@
1#ifndef _PERF_KEYSYMS_H_
2#define _PERF_KEYSYMS_H_ 1
3
4#include "libslang.h"
5
6#define K_DOWN SL_KEY_DOWN
7#define K_END SL_KEY_END
8#define K_ENTER '\r'
9#define K_ESC 033
10#define K_F1 SL_KEY_F(1)
11#define K_HOME SL_KEY_HOME
12#define K_LEFT SL_KEY_LEFT
13#define K_PGDN SL_KEY_NPAGE
14#define K_PGUP SL_KEY_PPAGE
15#define K_RIGHT SL_KEY_RIGHT
16#define K_TAB '\t'
17#define K_UNTAB SL_KEY_UNTAB
18#define K_UP SL_KEY_UP
19#define K_BKSPC 0x7f
20#define K_DEL SL_KEY_DELETE
21
22/* Not really keys */
23#define K_TIMER -1
24#define K_ERROR -2
25#define K_RESIZE -3
26
27#endif /* _PERF_KEYSYMS_H_ */
diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/util/ui/libslang.h
deleted file mode 100644
index 4d54b6450f5b..000000000000
--- a/tools/perf/util/ui/libslang.h
+++ /dev/null
@@ -1,29 +0,0 @@
1#ifndef _PERF_UI_SLANG_H_
2#define _PERF_UI_SLANG_H_ 1
3/*
4 * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks
5 * the build if it isn't defined. Use the equivalent one that glibc
6 * has on features.h.
7 */
8#include <features.h>
9#ifndef HAVE_LONG_LONG
10#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
11#endif
12#include <slang.h>
13
14#if SLANG_VERSION < 20104
15#define slsmg_printf(msg, args...) \
16 SLsmg_printf((char *)(msg), ##args)
17#define slsmg_write_nstring(msg, len) \
18 SLsmg_write_nstring((char *)(msg), len)
19#define sltt_set_color(obj, name, fg, bg) \
20 SLtt_set_color(obj,(char *)(name), (char *)(fg), (char *)(bg))
21#else
22#define slsmg_printf SLsmg_printf
23#define slsmg_write_nstring SLsmg_write_nstring
24#define sltt_set_color SLtt_set_color
25#endif
26
27#define SL_KEY_UNTAB 0x1000
28
29#endif /* _PERF_UI_SLANG_H_ */
diff --git a/tools/perf/util/ui/progress.c b/tools/perf/util/ui/progress.c
deleted file mode 100644
index 13aa64e50e11..000000000000
--- a/tools/perf/util/ui/progress.c
+++ /dev/null
@@ -1,32 +0,0 @@
1#include "../cache.h"
2#include "progress.h"
3#include "libslang.h"
4#include "ui.h"
5#include "browser.h"
6
7void ui_progress__update(u64 curr, u64 total, const char *title)
8{
9 int bar, y;
10 /*
11 * FIXME: We should have a per UI backend way of showing progress,
12 * stdio will just show a percentage as NN%, etc.
13 */
14 if (use_browser <= 0)
15 return;
16
17 if (total == 0)
18 return;
19
20 ui__refresh_dimensions(true);
21 pthread_mutex_lock(&ui__lock);
22 y = SLtt_Screen_Rows / 2 - 2;
23 SLsmg_set_color(0);
24 SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols);
25 SLsmg_gotorc(y++, 1);
26 SLsmg_write_string((char *)title);
27 SLsmg_set_color(HE_COLORSET_SELECTED);
28 bar = ((SLtt_Screen_Cols - 2) * curr) / total;
29 SLsmg_fill_region(y, 1, 1, bar, ' ');
30 SLsmg_refresh();
31 pthread_mutex_unlock(&ui__lock);
32}
diff --git a/tools/perf/util/ui/progress.h b/tools/perf/util/ui/progress.h
deleted file mode 100644
index d9c205b59aa1..000000000000
--- a/tools/perf/util/ui/progress.h
+++ /dev/null
@@ -1,8 +0,0 @@
1#ifndef _PERF_UI_PROGRESS_H_
2#define _PERF_UI_PROGRESS_H_ 1
3
4#include <../types.h>
5
6void ui_progress__update(u64 curr, u64 total, const char *title);
7
8#endif
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/util/ui/setup.c
deleted file mode 100644
index 85a69faa09aa..000000000000
--- a/tools/perf/util/ui/setup.c
+++ /dev/null
@@ -1,155 +0,0 @@
1#include <newt.h>
2#include <signal.h>
3#include <stdbool.h>
4
5#include "../cache.h"
6#include "../debug.h"
7#include "browser.h"
8#include "helpline.h"
9#include "ui.h"
10#include "util.h"
11#include "libslang.h"
12#include "keysyms.h"
13
14pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
15
16static volatile int ui__need_resize;
17
18void ui__refresh_dimensions(bool force)
19{
20 if (force || ui__need_resize) {
21 ui__need_resize = 0;
22 pthread_mutex_lock(&ui__lock);
23 SLtt_get_screen_size();
24 SLsmg_reinit_smg();
25 pthread_mutex_unlock(&ui__lock);
26 }
27}
28
29static void ui__sigwinch(int sig __used)
30{
31 ui__need_resize = 1;
32}
33
34static void ui__setup_sigwinch(void)
35{
36 static bool done;
37
38 if (done)
39 return;
40
41 done = true;
42 pthread__unblock_sigwinch();
43 signal(SIGWINCH, ui__sigwinch);
44}
45
46int ui__getch(int delay_secs)
47{
48 struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL;
49 fd_set read_set;
50 int err, key;
51
52 ui__setup_sigwinch();
53
54 FD_ZERO(&read_set);
55 FD_SET(0, &read_set);
56
57 if (delay_secs) {
58 timeout.tv_sec = delay_secs;
59 timeout.tv_usec = 0;
60 }
61
62 err = select(1, &read_set, NULL, NULL, ptimeout);
63
64 if (err == 0)
65 return K_TIMER;
66
67 if (err == -1) {
68 if (errno == EINTR)
69 return K_RESIZE;
70 return K_ERROR;
71 }
72
73 key = SLang_getkey();
74 if (key != K_ESC)
75 return key;
76
77 FD_ZERO(&read_set);
78 FD_SET(0, &read_set);
79 timeout.tv_sec = 0;
80 timeout.tv_usec = 20;
81 err = select(1, &read_set, NULL, NULL, &timeout);
82 if (err == 0)
83 return K_ESC;
84
85 SLang_ungetkey(key);
86 return SLkp_getkey();
87}
88
89static void newt_suspend(void *d __used)
90{
91 newtSuspend();
92 raise(SIGTSTP);
93 newtResume();
94}
95
96static int ui__init(void)
97{
98 int err = SLkp_init();
99
100 if (err < 0)
101 goto out;
102
103 SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
104out:
105 return err;
106}
107
108static void ui__exit(void)
109{
110 SLtt_set_cursor_visibility(1);
111 SLsmg_refresh();
112 SLsmg_reset_smg();
113 SLang_reset_tty();
114}
115
116static void ui__signal(int sig)
117{
118 ui__exit();
119 psignal(sig, "perf");
120 exit(0);
121}
122
123void setup_browser(bool fallback_to_pager)
124{
125 if (!isatty(1) || !use_browser || dump_trace) {
126 use_browser = 0;
127 if (fallback_to_pager)
128 setup_pager();
129 return;
130 }
131
132 use_browser = 1;
133 newtInit();
134 ui__init();
135 newtSetSuspendCallback(newt_suspend, NULL);
136 ui_helpline__init();
137 ui_browser__init();
138
139 signal(SIGSEGV, ui__signal);
140 signal(SIGFPE, ui__signal);
141 signal(SIGINT, ui__signal);
142 signal(SIGQUIT, ui__signal);
143 signal(SIGTERM, ui__signal);
144}
145
146void exit_browser(bool wait_for_ok)
147{
148 if (use_browser > 0) {
149 if (wait_for_ok)
150 ui__question_window("Fatal Error",
151 ui_helpline__last_msg,
152 "Press any key...", 0);
153 ui__exit();
154 }
155}
diff --git a/tools/perf/util/ui/ui.h b/tools/perf/util/ui/ui.h
deleted file mode 100644
index 7b67045479f6..000000000000
--- a/tools/perf/util/ui/ui.h
+++ /dev/null
@@ -1,11 +0,0 @@
1#ifndef _PERF_UI_H_
2#define _PERF_UI_H_ 1
3
4#include <pthread.h>
5#include <stdbool.h>
6
7extern pthread_mutex_t ui__lock;
8
9void ui__refresh_dimensions(bool force);
10
11#endif /* _PERF_UI_H_ */
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c
deleted file mode 100644
index ad4374a16bb0..000000000000
--- a/tools/perf/util/ui/util.c
+++ /dev/null
@@ -1,250 +0,0 @@
1#include "../util.h"
2#include <signal.h>
3#include <stdbool.h>
4#include <string.h>
5#include <sys/ttydefaults.h>
6
7#include "../cache.h"
8#include "../debug.h"
9#include "browser.h"
10#include "keysyms.h"
11#include "helpline.h"
12#include "ui.h"
13#include "util.h"
14#include "libslang.h"
15
16static void ui_browser__argv_write(struct ui_browser *browser,
17 void *entry, int row)
18{
19 char **arg = entry;
20 bool current_entry = ui_browser__is_current_entry(browser, row);
21
22 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
23 HE_COLORSET_NORMAL);
24 slsmg_write_nstring(*arg, browser->width);
25}
26
27static int popup_menu__run(struct ui_browser *menu)
28{
29 int key;
30
31 if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0)
32 return -1;
33
34 while (1) {
35 key = ui_browser__run(menu, 0);
36
37 switch (key) {
38 case K_RIGHT:
39 case K_ENTER:
40 key = menu->index;
41 break;
42 case K_LEFT:
43 case K_ESC:
44 case 'q':
45 case CTRL('c'):
46 key = -1;
47 break;
48 default:
49 continue;
50 }
51
52 break;
53 }
54
55 ui_browser__hide(menu);
56 return key;
57}
58
59int ui__popup_menu(int argc, char * const argv[])
60{
61 struct ui_browser menu = {
62 .entries = (void *)argv,
63 .refresh = ui_browser__argv_refresh,
64 .seek = ui_browser__argv_seek,
65 .write = ui_browser__argv_write,
66 .nr_entries = argc,
67 };
68
69 return popup_menu__run(&menu);
70}
71
72int ui_browser__input_window(const char *title, const char *text, char *input,
73 const char *exit_msg, int delay_secs)
74{
75 int x, y, len, key;
76 int max_len = 60, nr_lines = 0;
77 static char buf[50];
78 const char *t;
79
80 t = text;
81 while (1) {
82 const char *sep = strchr(t, '\n');
83
84 if (sep == NULL)
85 sep = strchr(t, '\0');
86 len = sep - t;
87 if (max_len < len)
88 max_len = len;
89 ++nr_lines;
90 if (*sep == '\0')
91 break;
92 t = sep + 1;
93 }
94
95 max_len += 2;
96 nr_lines += 8;
97 y = SLtt_Screen_Rows / 2 - nr_lines / 2;
98 x = SLtt_Screen_Cols / 2 - max_len / 2;
99
100 SLsmg_set_color(0);
101 SLsmg_draw_box(y, x++, nr_lines, max_len);
102 if (title) {
103 SLsmg_gotorc(y, x + 1);
104 SLsmg_write_string((char *)title);
105 }
106 SLsmg_gotorc(++y, x);
107 nr_lines -= 7;
108 max_len -= 2;
109 SLsmg_write_wrapped_string((unsigned char *)text, y, x,
110 nr_lines, max_len, 1);
111 y += nr_lines;
112 len = 5;
113 while (len--) {
114 SLsmg_gotorc(y + len - 1, x);
115 SLsmg_write_nstring((char *)" ", max_len);
116 }
117 SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
118
119 SLsmg_gotorc(y + 3, x);
120 SLsmg_write_nstring((char *)exit_msg, max_len);
121 SLsmg_refresh();
122
123 x += 2;
124 len = 0;
125 key = ui__getch(delay_secs);
126 while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
127 if (key == K_BKSPC) {
128 if (len == 0)
129 goto next_key;
130 SLsmg_gotorc(y, x + --len);
131 SLsmg_write_char(' ');
132 } else {
133 buf[len] = key;
134 SLsmg_gotorc(y, x + len++);
135 SLsmg_write_char(key);
136 }
137 SLsmg_refresh();
138
139 /* XXX more graceful overflow handling needed */
140 if (len == sizeof(buf) - 1) {
141 ui_helpline__push("maximum size of symbol name reached!");
142 key = K_ENTER;
143 break;
144 }
145next_key:
146 key = ui__getch(delay_secs);
147 }
148
149 buf[len] = '\0';
150 strncpy(input, buf, len+1);
151 return key;
152}
153
154int ui__question_window(const char *title, const char *text,
155 const char *exit_msg, int delay_secs)
156{
157 int x, y;
158 int max_len = 0, nr_lines = 0;
159 const char *t;
160
161 t = text;
162 while (1) {
163 const char *sep = strchr(t, '\n');
164 int len;
165
166 if (sep == NULL)
167 sep = strchr(t, '\0');
168 len = sep - t;
169 if (max_len < len)
170 max_len = len;
171 ++nr_lines;
172 if (*sep == '\0')
173 break;
174 t = sep + 1;
175 }
176
177 max_len += 2;
178 nr_lines += 4;
179 y = SLtt_Screen_Rows / 2 - nr_lines / 2,
180 x = SLtt_Screen_Cols / 2 - max_len / 2;
181
182 SLsmg_set_color(0);
183 SLsmg_draw_box(y, x++, nr_lines, max_len);
184 if (title) {
185 SLsmg_gotorc(y, x + 1);
186 SLsmg_write_string((char *)title);
187 }
188 SLsmg_gotorc(++y, x);
189 nr_lines -= 2;
190 max_len -= 2;
191 SLsmg_write_wrapped_string((unsigned char *)text, y, x,
192 nr_lines, max_len, 1);
193 SLsmg_gotorc(y + nr_lines - 2, x);
194 SLsmg_write_nstring((char *)" ", max_len);
195 SLsmg_gotorc(y + nr_lines - 1, x);
196 SLsmg_write_nstring((char *)exit_msg, max_len);
197 SLsmg_refresh();
198 return ui__getch(delay_secs);
199}
200
201int ui__help_window(const char *text)
202{
203 return ui__question_window("Help", text, "Press any key...", 0);
204}
205
206int ui__dialog_yesno(const char *msg)
207{
208 return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0);
209}
210
211int __ui__warning(const char *title, const char *format, va_list args)
212{
213 char *s;
214
215 if (use_browser > 0 && vasprintf(&s, format, args) > 0) {
216 int key;
217
218 pthread_mutex_lock(&ui__lock);
219 key = ui__question_window(title, s, "Press any key...", 0);
220 pthread_mutex_unlock(&ui__lock);
221 free(s);
222 return key;
223 }
224
225 fprintf(stderr, "%s:\n", title);
226 vfprintf(stderr, format, args);
227 return K_ESC;
228}
229
230int ui__warning(const char *format, ...)
231{
232 int key;
233 va_list args;
234
235 va_start(args, format);
236 key = __ui__warning("Warning", format, args);
237 va_end(args);
238 return key;
239}
240
241int ui__error(const char *format, ...)
242{
243 int key;
244 va_list args;
245
246 va_start(args, format);
247 key = __ui__warning("Error", format, args);
248 va_end(args);
249 return key;
250}
diff --git a/tools/perf/util/ui/util.h b/tools/perf/util/ui/util.h
deleted file mode 100644
index 2d1738bd71c8..000000000000
--- a/tools/perf/util/ui/util.h
+++ /dev/null
@@ -1,14 +0,0 @@
1#ifndef _PERF_UI_UTIL_H_
2#define _PERF_UI_UTIL_H_ 1
3
4#include <stdarg.h>
5
6int ui__getch(int delay_secs);
7int ui__popup_menu(int argc, char * const argv[]);
8int ui__help_window(const char *text);
9int ui__dialog_yesno(const char *msg);
10int ui__question_window(const char *title, const char *text,
11 const char *exit_msg, int delay_secs);
12int __ui__warning(const char *title, const char *format, va_list args);
13
14#endif /* _PERF_UI_UTIL_H_ */
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
index 52bb07c6442a..4007aca8e0ca 100644
--- a/tools/perf/util/usage.c
+++ b/tools/perf/util/usage.c
@@ -82,41 +82,3 @@ void warning(const char *warn, ...)
82 warn_routine(warn, params); 82 warn_routine(warn, params);
83 va_end(params); 83 va_end(params);
84} 84}
85
86uid_t parse_target_uid(const char *str, const char *tid, const char *pid)
87{
88 struct passwd pwd, *result;
89 char buf[1024];
90
91 if (str == NULL)
92 return UINT_MAX;
93
94 /* UID and PID are mutually exclusive */
95 if (tid || pid) {
96 ui__warning("PID/TID switch overriding UID\n");
97 sleep(1);
98 return UINT_MAX;
99 }
100
101 getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
102
103 if (result == NULL) {
104 char *endptr;
105 int uid = strtol(str, &endptr, 10);
106
107 if (*endptr != '\0') {
108 ui__error("Invalid user %s\n", str);
109 return UINT_MAX - 1;
110 }
111
112 getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
113
114 if (result == NULL) {
115 ui__error("Problems obtaining information for user %s\n",
116 str);
117 return UINT_MAX - 1;
118 }
119 }
120
121 return result->pw_uid;
122}
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 8109a907841e..d03599fbe78b 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -148,3 +148,13 @@ int readn(int fd, void *buf, size_t n)
148 148
149 return buf - buf_start; 149 return buf - buf_start;
150} 150}
151
152size_t hex_width(u64 v)
153{
154 size_t n = 1;
155
156 while ((v >>= 4))
157 ++n;
158
159 return n;
160}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 0f99f394d8e0..2daaedb83d84 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -74,7 +74,6 @@
74#include <netinet/tcp.h> 74#include <netinet/tcp.h>
75#include <arpa/inet.h> 75#include <arpa/inet.h>
76#include <netdb.h> 76#include <netdb.h>
77#include <pwd.h>
78#include <inttypes.h> 77#include <inttypes.h>
79#include "../../../include/linux/magic.h" 78#include "../../../include/linux/magic.h"
80#include "types.h" 79#include "types.h"
@@ -249,8 +248,6 @@ struct perf_event_attr;
249 248
250void event_attr_init(struct perf_event_attr *attr); 249void event_attr_init(struct perf_event_attr *attr);
251 250
252uid_t parse_target_uid(const char *str, const char *tid, const char *pid);
253
254#define _STR(x) #x 251#define _STR(x) #x
255#define STR(x) _STR(x) 252#define STR(x) _STR(x)
256 253
@@ -265,4 +262,6 @@ bool is_power_of_2(unsigned long n)
265 return (n != 0 && ((n & (n - 1)) == 0)); 262 return (n != 0 && ((n & (n - 1)) == 0));
266} 263}
267 264
265size_t hex_width(u64 v);
266
268#endif 267#endif