diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-11-17 10:31:51 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-11-17 15:31:59 -0500 |
commit | 763d8960a17126e73e7d9cd6b66e390196f48894 (patch) | |
tree | 5f05bd89b967cd7d1f29f80cd0a410cc205a8cdd /tools/perf/util/annotate.c | |
parent | 9c2fb451bda0aa60127e63e44993401818326e91 (diff) |
perf annotate: Add per arch instructions annotate handlers
Another step in supporting cross annotation.
The arch specific tables are put in:
tools/perf/arch/$ARCH/annotation/instructions.c
which, so far, just plug instructions to a bunch of parsers/formatters,
but may have more as the need arises.
This is an alternative implementation to a previous attempt made by Ravi
Bangoria.
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Chris Riyder <chris.ryder@arm.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kim Phillips <kim.phillips@arm.com>
Cc: Markus Trippelsdorf <markus@trippelsdorf.de>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Cc: Pawel Moll <pawel.moll@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com>
Cc: Russell King <rmk+kernel@arm.linux.org.uk>
Cc: Taeung Song <treeze.taeung@gmail.com>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/n/tip-g3wt282lfa51j4qd0813e3az@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/annotate.c')
-rw-r--r-- | tools/perf/util/annotate.c | 136 |
1 files changed, 30 insertions, 106 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 72769762ece9..095d90a9077f 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -28,20 +28,36 @@ const char *disassembler_style; | |||
28 | const char *objdump_path; | 28 | const char *objdump_path; |
29 | static regex_t file_lineno; | 29 | static regex_t file_lineno; |
30 | 30 | ||
31 | static struct ins *ins__find(const char *name); | 31 | static struct ins *ins__find(struct arch *arch, const char *name); |
32 | static int disasm_line__parse(char *line, char **namep, char **rawp); | 32 | static int disasm_line__parse(char *line, char **namep, char **rawp); |
33 | 33 | ||
34 | struct arch { | 34 | struct arch { |
35 | const char *name; | 35 | const char *name; |
36 | struct ins *instructions; | ||
37 | size_t nr_instructions; | ||
38 | bool sorted_instructions; | ||
36 | struct { | 39 | struct { |
37 | char comment_char; | 40 | char comment_char; |
38 | char skip_functions_char; | 41 | char skip_functions_char; |
39 | } objdump; | 42 | } objdump; |
40 | }; | 43 | }; |
41 | 44 | ||
45 | static struct ins_ops call_ops; | ||
46 | static struct ins_ops dec_ops; | ||
47 | static struct ins_ops jump_ops; | ||
48 | static struct ins_ops mov_ops; | ||
49 | static struct ins_ops nop_ops; | ||
50 | static struct ins_ops lock_ops; | ||
51 | static struct ins_ops ret_ops; | ||
52 | |||
53 | #include "arch/arm/annotate/instructions.c" | ||
54 | #include "arch/x86/annotate/instructions.c" | ||
55 | |||
42 | static struct arch architectures[] = { | 56 | static struct arch architectures[] = { |
43 | { | 57 | { |
44 | .name = "arm", | 58 | .name = "arm", |
59 | .instructions = arm__instructions, | ||
60 | .nr_instructions = ARRAY_SIZE(arm__instructions), | ||
45 | .objdump = { | 61 | .objdump = { |
46 | .comment_char = ';', | 62 | .comment_char = ';', |
47 | .skip_functions_char = '+', | 63 | .skip_functions_char = '+', |
@@ -49,6 +65,8 @@ static struct arch architectures[] = { | |||
49 | }, | 65 | }, |
50 | { | 66 | { |
51 | .name = "x86", | 67 | .name = "x86", |
68 | .instructions = x86__instructions, | ||
69 | .nr_instructions = ARRAY_SIZE(x86__instructions), | ||
52 | .objdump = { | 70 | .objdump = { |
53 | .comment_char = '#', | 71 | .comment_char = '#', |
54 | }, | 72 | }, |
@@ -209,7 +227,7 @@ static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map * | |||
209 | if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) | 227 | if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) |
210 | goto out_free_ops; | 228 | goto out_free_ops; |
211 | 229 | ||
212 | ops->locked.ins = ins__find(name); | 230 | ops->locked.ins = ins__find(arch, name); |
213 | free(name); | 231 | free(name); |
214 | 232 | ||
215 | if (ops->locked.ins == NULL) | 233 | if (ops->locked.ins == NULL) |
@@ -385,99 +403,6 @@ bool ins__is_ret(const struct ins *ins) | |||
385 | return ins->ops == &ret_ops; | 403 | return ins->ops == &ret_ops; |
386 | } | 404 | } |
387 | 405 | ||
388 | static struct ins instructions[] = { | ||
389 | { .name = "add", .ops = &mov_ops, }, | ||
390 | { .name = "addl", .ops = &mov_ops, }, | ||
391 | { .name = "addq", .ops = &mov_ops, }, | ||
392 | { .name = "addw", .ops = &mov_ops, }, | ||
393 | { .name = "and", .ops = &mov_ops, }, | ||
394 | #ifdef __arm__ | ||
395 | { .name = "b", .ops = &jump_ops, }, // might also be a call | ||
396 | { .name = "bcc", .ops = &jump_ops, }, | ||
397 | { .name = "bcs", .ops = &jump_ops, }, | ||
398 | { .name = "beq", .ops = &jump_ops, }, | ||
399 | { .name = "bge", .ops = &jump_ops, }, | ||
400 | { .name = "bgt", .ops = &jump_ops, }, | ||
401 | { .name = "bhi", .ops = &jump_ops, }, | ||
402 | { .name = "bl", .ops = &call_ops, }, | ||
403 | { .name = "bls", .ops = &jump_ops, }, | ||
404 | { .name = "blt", .ops = &jump_ops, }, | ||
405 | { .name = "blx", .ops = &call_ops, }, | ||
406 | { .name = "bne", .ops = &jump_ops, }, | ||
407 | #endif | ||
408 | { .name = "bts", .ops = &mov_ops, }, | ||
409 | { .name = "call", .ops = &call_ops, }, | ||
410 | { .name = "callq", .ops = &call_ops, }, | ||
411 | { .name = "cmp", .ops = &mov_ops, }, | ||
412 | { .name = "cmpb", .ops = &mov_ops, }, | ||
413 | { .name = "cmpl", .ops = &mov_ops, }, | ||
414 | { .name = "cmpq", .ops = &mov_ops, }, | ||
415 | { .name = "cmpw", .ops = &mov_ops, }, | ||
416 | { .name = "cmpxch", .ops = &mov_ops, }, | ||
417 | { .name = "dec", .ops = &dec_ops, }, | ||
418 | { .name = "decl", .ops = &dec_ops, }, | ||
419 | { .name = "imul", .ops = &mov_ops, }, | ||
420 | { .name = "inc", .ops = &dec_ops, }, | ||
421 | { .name = "incl", .ops = &dec_ops, }, | ||
422 | { .name = "ja", .ops = &jump_ops, }, | ||
423 | { .name = "jae", .ops = &jump_ops, }, | ||
424 | { .name = "jb", .ops = &jump_ops, }, | ||
425 | { .name = "jbe", .ops = &jump_ops, }, | ||
426 | { .name = "jc", .ops = &jump_ops, }, | ||
427 | { .name = "jcxz", .ops = &jump_ops, }, | ||
428 | { .name = "je", .ops = &jump_ops, }, | ||
429 | { .name = "jecxz", .ops = &jump_ops, }, | ||
430 | { .name = "jg", .ops = &jump_ops, }, | ||
431 | { .name = "jge", .ops = &jump_ops, }, | ||
432 | { .name = "jl", .ops = &jump_ops, }, | ||
433 | { .name = "jle", .ops = &jump_ops, }, | ||
434 | { .name = "jmp", .ops = &jump_ops, }, | ||
435 | { .name = "jmpq", .ops = &jump_ops, }, | ||
436 | { .name = "jna", .ops = &jump_ops, }, | ||
437 | { .name = "jnae", .ops = &jump_ops, }, | ||
438 | { .name = "jnb", .ops = &jump_ops, }, | ||
439 | { .name = "jnbe", .ops = &jump_ops, }, | ||
440 | { .name = "jnc", .ops = &jump_ops, }, | ||
441 | { .name = "jne", .ops = &jump_ops, }, | ||
442 | { .name = "jng", .ops = &jump_ops, }, | ||
443 | { .name = "jnge", .ops = &jump_ops, }, | ||
444 | { .name = "jnl", .ops = &jump_ops, }, | ||
445 | { .name = "jnle", .ops = &jump_ops, }, | ||
446 | { .name = "jno", .ops = &jump_ops, }, | ||
447 | { .name = "jnp", .ops = &jump_ops, }, | ||
448 | { .name = "jns", .ops = &jump_ops, }, | ||
449 | { .name = "jnz", .ops = &jump_ops, }, | ||
450 | { .name = "jo", .ops = &jump_ops, }, | ||
451 | { .name = "jp", .ops = &jump_ops, }, | ||
452 | { .name = "jpe", .ops = &jump_ops, }, | ||
453 | { .name = "jpo", .ops = &jump_ops, }, | ||
454 | { .name = "jrcxz", .ops = &jump_ops, }, | ||
455 | { .name = "js", .ops = &jump_ops, }, | ||
456 | { .name = "jz", .ops = &jump_ops, }, | ||
457 | { .name = "lea", .ops = &mov_ops, }, | ||
458 | { .name = "lock", .ops = &lock_ops, }, | ||
459 | { .name = "mov", .ops = &mov_ops, }, | ||
460 | { .name = "movb", .ops = &mov_ops, }, | ||
461 | { .name = "movdqa",.ops = &mov_ops, }, | ||
462 | { .name = "movl", .ops = &mov_ops, }, | ||
463 | { .name = "movq", .ops = &mov_ops, }, | ||
464 | { .name = "movslq", .ops = &mov_ops, }, | ||
465 | { .name = "movzbl", .ops = &mov_ops, }, | ||
466 | { .name = "movzwl", .ops = &mov_ops, }, | ||
467 | { .name = "nop", .ops = &nop_ops, }, | ||
468 | { .name = "nopl", .ops = &nop_ops, }, | ||
469 | { .name = "nopw", .ops = &nop_ops, }, | ||
470 | { .name = "or", .ops = &mov_ops, }, | ||
471 | { .name = "orl", .ops = &mov_ops, }, | ||
472 | { .name = "test", .ops = &mov_ops, }, | ||
473 | { .name = "testb", .ops = &mov_ops, }, | ||
474 | { .name = "testl", .ops = &mov_ops, }, | ||
475 | { .name = "xadd", .ops = &mov_ops, }, | ||
476 | { .name = "xbeginl", .ops = &jump_ops, }, | ||
477 | { .name = "xbeginq", .ops = &jump_ops, }, | ||
478 | { .name = "retq", .ops = &ret_ops, }, | ||
479 | }; | ||
480 | |||
481 | static int ins__key_cmp(const void *name, const void *insp) | 406 | static int ins__key_cmp(const void *name, const void *insp) |
482 | { | 407 | { |
483 | const struct ins *ins = insp; | 408 | const struct ins *ins = insp; |
@@ -493,24 +418,23 @@ static int ins__cmp(const void *a, const void *b) | |||
493 | return strcmp(ia->name, ib->name); | 418 | return strcmp(ia->name, ib->name); |
494 | } | 419 | } |
495 | 420 | ||
496 | static void ins__sort(void) | 421 | static void ins__sort(struct arch *arch) |
497 | { | 422 | { |
498 | const int nmemb = ARRAY_SIZE(instructions); | 423 | const int nmemb = arch->nr_instructions; |
499 | 424 | ||
500 | qsort(instructions, nmemb, sizeof(struct ins), ins__cmp); | 425 | qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp); |
501 | } | 426 | } |
502 | 427 | ||
503 | static struct ins *ins__find(const char *name) | 428 | static struct ins *ins__find(struct arch *arch, const char *name) |
504 | { | 429 | { |
505 | const int nmemb = ARRAY_SIZE(instructions); | 430 | const int nmemb = arch->nr_instructions; |
506 | static bool sorted; | ||
507 | 431 | ||
508 | if (!sorted) { | 432 | if (!arch->sorted_instructions) { |
509 | ins__sort(); | 433 | ins__sort(arch); |
510 | sorted = true; | 434 | arch->sorted_instructions = true; |
511 | } | 435 | } |
512 | 436 | ||
513 | return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp); | 437 | return bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp); |
514 | } | 438 | } |
515 | 439 | ||
516 | static int arch__key_cmp(const void *name, const void *archp) | 440 | static int arch__key_cmp(const void *name, const void *archp) |
@@ -767,7 +691,7 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) | |||
767 | 691 | ||
768 | static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map *map) | 692 | static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map *map) |
769 | { | 693 | { |
770 | dl->ins = ins__find(dl->name); | 694 | dl->ins = ins__find(arch, dl->name); |
771 | 695 | ||
772 | if (dl->ins == NULL) | 696 | if (dl->ins == NULL) |
773 | return; | 697 | return; |