diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-11-16 13:39:50 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2016-11-17 15:12:50 -0500 |
commit | 786c1b51844d858041166057c0c79e93c2015013 (patch) | |
tree | 5e7312f542b6c5264276754476e8d3240bac520d /tools/perf/util/annotate.c | |
parent | 6a6b12e2125591e24891e6860410795ea53aed11 (diff) |
perf annotate: Start supporting cross arch annotation
Introduce a 'struct arch', where arch specific stuff will live, starting
with objdump's choice of comment delimitation character, that is '#' in
x86 while a ';' in arm.
This has some bits and pieces from a patch submitted by Ravi.
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: Taeung Song <treeze.taeung@gmail.com>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/n/tip-f337tzjjcl8vtapgvjxmhrbx@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 | 114 |
1 files changed, 96 insertions, 18 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index aeb5a441bd74..1ba41a27214d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -18,9 +18,11 @@ | |||
18 | #include "annotate.h" | 18 | #include "annotate.h" |
19 | #include "evsel.h" | 19 | #include "evsel.h" |
20 | #include "block-range.h" | 20 | #include "block-range.h" |
21 | #include "arch/common.h" | ||
21 | #include <regex.h> | 22 | #include <regex.h> |
22 | #include <pthread.h> | 23 | #include <pthread.h> |
23 | #include <linux/bitops.h> | 24 | #include <linux/bitops.h> |
25 | #include <sys/utsname.h> | ||
24 | 26 | ||
25 | const char *disassembler_style; | 27 | const char *disassembler_style; |
26 | const char *objdump_path; | 28 | const char *objdump_path; |
@@ -29,6 +31,28 @@ static regex_t file_lineno; | |||
29 | static struct ins *ins__find(const char *name); | 31 | static struct ins *ins__find(const char *name); |
30 | static int disasm_line__parse(char *line, char **namep, char **rawp); | 32 | static int disasm_line__parse(char *line, char **namep, char **rawp); |
31 | 33 | ||
34 | struct arch { | ||
35 | const char *name; | ||
36 | struct { | ||
37 | char comment_char; | ||
38 | } objdump; | ||
39 | }; | ||
40 | |||
41 | static struct arch architectures[] = { | ||
42 | { | ||
43 | .name = "arm", | ||
44 | .objdump = { | ||
45 | .comment_char = ';', | ||
46 | }, | ||
47 | }, | ||
48 | { | ||
49 | .name = "x86", | ||
50 | .objdump = { | ||
51 | .comment_char = '#', | ||
52 | }, | ||
53 | }, | ||
54 | }; | ||
55 | |||
32 | static void ins__delete(struct ins_operands *ops) | 56 | static void ins__delete(struct ins_operands *ops) |
33 | { | 57 | { |
34 | if (ops == NULL) | 58 | if (ops == NULL) |
@@ -54,7 +78,7 @@ int ins__scnprintf(struct ins *ins, char *bf, size_t size, | |||
54 | return ins__raw_scnprintf(ins, bf, size, ops); | 78 | return ins__raw_scnprintf(ins, bf, size, ops); |
55 | } | 79 | } |
56 | 80 | ||
57 | static int call__parse(struct ins_operands *ops, struct map *map) | 81 | static int call__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map) |
58 | { | 82 | { |
59 | char *endptr, *tok, *name; | 83 | char *endptr, *tok, *name; |
60 | 84 | ||
@@ -118,7 +142,7 @@ bool ins__is_call(const struct ins *ins) | |||
118 | return ins->ops == &call_ops; | 142 | return ins->ops == &call_ops; |
119 | } | 143 | } |
120 | 144 | ||
121 | static int jump__parse(struct ins_operands *ops, struct map *map __maybe_unused) | 145 | static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map __maybe_unused) |
122 | { | 146 | { |
123 | const char *s = strchr(ops->raw, '+'); | 147 | const char *s = strchr(ops->raw, '+'); |
124 | 148 | ||
@@ -173,7 +197,7 @@ static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) | |||
173 | return 0; | 197 | return 0; |
174 | } | 198 | } |
175 | 199 | ||
176 | static int lock__parse(struct ins_operands *ops, struct map *map) | 200 | static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map *map) |
177 | { | 201 | { |
178 | char *name; | 202 | char *name; |
179 | 203 | ||
@@ -194,7 +218,7 @@ static int lock__parse(struct ins_operands *ops, struct map *map) | |||
194 | return 0; | 218 | return 0; |
195 | 219 | ||
196 | if (ops->locked.ins->ops->parse && | 220 | if (ops->locked.ins->ops->parse && |
197 | ops->locked.ins->ops->parse(ops->locked.ops, map) < 0) | 221 | ops->locked.ins->ops->parse(arch, ops->locked.ops, map) < 0) |
198 | goto out_free_ops; | 222 | goto out_free_ops; |
199 | 223 | ||
200 | return 0; | 224 | return 0; |
@@ -237,7 +261,7 @@ static struct ins_ops lock_ops = { | |||
237 | .scnprintf = lock__scnprintf, | 261 | .scnprintf = lock__scnprintf, |
238 | }; | 262 | }; |
239 | 263 | ||
240 | static int mov__parse(struct ins_operands *ops, struct map *map __maybe_unused) | 264 | static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map *map __maybe_unused) |
241 | { | 265 | { |
242 | char *s = strchr(ops->raw, ','), *target, *comment, prev; | 266 | char *s = strchr(ops->raw, ','), *target, *comment, prev; |
243 | 267 | ||
@@ -252,11 +276,7 @@ static int mov__parse(struct ins_operands *ops, struct map *map __maybe_unused) | |||
252 | return -1; | 276 | return -1; |
253 | 277 | ||
254 | target = ++s; | 278 | target = ++s; |
255 | #ifdef __arm__ | 279 | comment = strchr(s, arch->objdump.comment_char); |
256 | comment = strchr(s, ';'); | ||
257 | #else | ||
258 | comment = strchr(s, '#'); | ||
259 | #endif | ||
260 | 280 | ||
261 | if (comment != NULL) | 281 | if (comment != NULL) |
262 | s = comment - 1; | 282 | s = comment - 1; |
@@ -304,7 +324,7 @@ static struct ins_ops mov_ops = { | |||
304 | .scnprintf = mov__scnprintf, | 324 | .scnprintf = mov__scnprintf, |
305 | }; | 325 | }; |
306 | 326 | ||
307 | static int dec__parse(struct ins_operands *ops, struct map *map __maybe_unused) | 327 | static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map __maybe_unused) |
308 | { | 328 | { |
309 | char *target, *comment, *s, prev; | 329 | char *target, *comment, *s, prev; |
310 | 330 | ||
@@ -492,6 +512,41 @@ static struct ins *ins__find(const char *name) | |||
492 | return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp); | 512 | return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp); |
493 | } | 513 | } |
494 | 514 | ||
515 | static int arch__key_cmp(const void *name, const void *archp) | ||
516 | { | ||
517 | const struct arch *arch = archp; | ||
518 | |||
519 | return strcmp(name, arch->name); | ||
520 | } | ||
521 | |||
522 | static int arch__cmp(const void *a, const void *b) | ||
523 | { | ||
524 | const struct arch *aa = a; | ||
525 | const struct arch *ab = b; | ||
526 | |||
527 | return strcmp(aa->name, ab->name); | ||
528 | } | ||
529 | |||
530 | static void arch__sort(void) | ||
531 | { | ||
532 | const int nmemb = ARRAY_SIZE(architectures); | ||
533 | |||
534 | qsort(architectures, nmemb, sizeof(struct arch), arch__cmp); | ||
535 | } | ||
536 | |||
537 | static struct arch *arch__find(const char *name) | ||
538 | { | ||
539 | const int nmemb = ARRAY_SIZE(architectures); | ||
540 | static bool sorted; | ||
541 | |||
542 | if (!sorted) { | ||
543 | arch__sort(); | ||
544 | sorted = true; | ||
545 | } | ||
546 | |||
547 | return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp); | ||
548 | } | ||
549 | |||
495 | int symbol__alloc_hist(struct symbol *sym) | 550 | int symbol__alloc_hist(struct symbol *sym) |
496 | { | 551 | { |
497 | struct annotation *notes = symbol__annotation(sym); | 552 | struct annotation *notes = symbol__annotation(sym); |
@@ -709,7 +764,7 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) | |||
709 | return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); | 764 | return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); |
710 | } | 765 | } |
711 | 766 | ||
712 | static void disasm_line__init_ins(struct disasm_line *dl, struct map *map) | 767 | static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map *map) |
713 | { | 768 | { |
714 | dl->ins = ins__find(dl->name); | 769 | dl->ins = ins__find(dl->name); |
715 | 770 | ||
@@ -719,7 +774,7 @@ static void disasm_line__init_ins(struct disasm_line *dl, struct map *map) | |||
719 | if (!dl->ins->ops) | 774 | if (!dl->ins->ops) |
720 | return; | 775 | return; |
721 | 776 | ||
722 | if (dl->ins->ops->parse && dl->ins->ops->parse(&dl->ops, map) < 0) | 777 | if (dl->ins->ops->parse && dl->ins->ops->parse(arch, &dl->ops, map) < 0) |
723 | dl->ins = NULL; | 778 | dl->ins = NULL; |
724 | } | 779 | } |
725 | 780 | ||
@@ -762,6 +817,7 @@ out_free_name: | |||
762 | 817 | ||
763 | static struct disasm_line *disasm_line__new(s64 offset, char *line, | 818 | static struct disasm_line *disasm_line__new(s64 offset, char *line, |
764 | size_t privsize, int line_nr, | 819 | size_t privsize, int line_nr, |
820 | struct arch *arch, | ||
765 | struct map *map) | 821 | struct map *map) |
766 | { | 822 | { |
767 | struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); | 823 | struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); |
@@ -777,7 +833,7 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, | |||
777 | if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0) | 833 | if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0) |
778 | goto out_free_line; | 834 | goto out_free_line; |
779 | 835 | ||
780 | disasm_line__init_ins(dl, map); | 836 | disasm_line__init_ins(dl, arch, map); |
781 | } | 837 | } |
782 | } | 838 | } |
783 | 839 | ||
@@ -1087,6 +1143,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st | |||
1087 | * The ops.raw part will be parsed further according to type of the instruction. | 1143 | * The ops.raw part will be parsed further according to type of the instruction. |
1088 | */ | 1144 | */ |
1089 | static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | 1145 | static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, |
1146 | struct arch *arch, | ||
1090 | FILE *file, size_t privsize, | 1147 | FILE *file, size_t privsize, |
1091 | int *line_nr) | 1148 | int *line_nr) |
1092 | { | 1149 | { |
@@ -1149,7 +1206,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | |||
1149 | parsed_line = tmp2 + 1; | 1206 | parsed_line = tmp2 + 1; |
1150 | } | 1207 | } |
1151 | 1208 | ||
1152 | dl = disasm_line__new(offset, parsed_line, privsize, *line_nr, map); | 1209 | dl = disasm_line__new(offset, parsed_line, privsize, *line_nr, arch, map); |
1153 | free(line); | 1210 | free(line); |
1154 | (*line_nr)++; | 1211 | (*line_nr)++; |
1155 | 1212 | ||
@@ -1280,10 +1337,23 @@ fallback: | |||
1280 | return 0; | 1337 | return 0; |
1281 | } | 1338 | } |
1282 | 1339 | ||
1283 | int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize) | 1340 | static const char *annotate__norm_arch(const char *arch_name) |
1341 | { | ||
1342 | struct utsname uts; | ||
1343 | |||
1344 | if (!arch_name) { /* Assume we are annotating locally. */ | ||
1345 | if (uname(&uts) < 0) | ||
1346 | return NULL; | ||
1347 | arch_name = uts.machine; | ||
1348 | } | ||
1349 | return normalize_arch((char *)arch_name); | ||
1350 | } | ||
1351 | |||
1352 | int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_name, size_t privsize) | ||
1284 | { | 1353 | { |
1285 | struct dso *dso = map->dso; | 1354 | struct dso *dso = map->dso; |
1286 | char command[PATH_MAX * 2]; | 1355 | char command[PATH_MAX * 2]; |
1356 | struct arch *arch = NULL; | ||
1287 | FILE *file; | 1357 | FILE *file; |
1288 | char symfs_filename[PATH_MAX]; | 1358 | char symfs_filename[PATH_MAX]; |
1289 | struct kcore_extract kce; | 1359 | struct kcore_extract kce; |
@@ -1297,6 +1367,14 @@ int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize) | |||
1297 | if (err) | 1367 | if (err) |
1298 | return err; | 1368 | return err; |
1299 | 1369 | ||
1370 | arch_name = annotate__norm_arch(arch_name); | ||
1371 | if (!arch_name) | ||
1372 | return -1; | ||
1373 | |||
1374 | arch = arch__find(arch_name); | ||
1375 | if (arch == NULL) | ||
1376 | return -ENOTSUP; | ||
1377 | |||
1300 | pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, | 1378 | pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, |
1301 | symfs_filename, sym->name, map->unmap_ip(map, sym->start), | 1379 | symfs_filename, sym->name, map->unmap_ip(map, sym->start), |
1302 | map->unmap_ip(map, sym->end)); | 1380 | map->unmap_ip(map, sym->end)); |
@@ -1395,7 +1473,7 @@ int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize) | |||
1395 | 1473 | ||
1396 | nline = 0; | 1474 | nline = 0; |
1397 | while (!feof(file)) { | 1475 | while (!feof(file)) { |
1398 | if (symbol__parse_objdump_line(sym, map, file, privsize, | 1476 | if (symbol__parse_objdump_line(sym, map, arch, file, privsize, |
1399 | &lineno) < 0) | 1477 | &lineno) < 0) |
1400 | break; | 1478 | break; |
1401 | nline++; | 1479 | nline++; |
@@ -1793,7 +1871,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, | |||
1793 | struct rb_root source_line = RB_ROOT; | 1871 | struct rb_root source_line = RB_ROOT; |
1794 | u64 len; | 1872 | u64 len; |
1795 | 1873 | ||
1796 | if (symbol__disassemble(sym, map, 0) < 0) | 1874 | if (symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), 0) < 0) |
1797 | return -1; | 1875 | return -1; |
1798 | 1876 | ||
1799 | len = symbol__size(sym); | 1877 | len = symbol__size(sym); |