diff options
author | Ingo Molnar <mingo@kernel.org> | 2016-11-23 23:09:31 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-11-23 23:09:31 -0500 |
commit | 47414424c53a70eceb0fc6e0a35a31a2b763d5b2 (patch) | |
tree | 07979aa784313ba03712df2b85a3b3f71f1733d6 /tools/perf/util/annotate.c | |
parent | 69e6cdd0cf16f645be39038e5ccc9379e3923d00 (diff) | |
parent | a407b0678bc1c39d70af5fdbe6421c164b69a8c0 (diff) |
Merge tag 'perf-core-for-mingo-20161123' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
New tool:
- 'perf sched timehist' provides an analysis of scheduling events.
Example usage:
perf sched record -- sleep 1
perf sched timehist
By default it shows the individual schedule events, including the wait
time (time between sched-out and next sched-in events for the task), the
task scheduling delay (time between wakeup and actually running) and run
time for the task:
time cpu task name wait time sch delay run time
[tid/pid] (msec) (msec) (msec)
-------- ------ ---------------- --------- --------- --------
1.874569 [0011] gcc[31949] 0.014 0.000 1.148
1.874591 [0010] gcc[31951] 0.000 0.000 0.024
1.874603 [0010] migration/10[59] 3.350 0.004 0.011
1.874604 [0011] <idle> 1.148 0.000 0.035
1.874723 [0005] <idle> 0.016 0.000 1.383
1.874746 [0005] gcc[31949] 0.153 0.078 0.022
...
Times are in msec.usec. (David Ahern, Namhyung Kim)
Improvements:
- Make 'perf c2c report' support -f/--force, to allow skipping the
ownership check for root users, for instance, just like the other
tools (Jiri Olsa)
- Allow sorting cachelines by total number of HITMs, in addition to
local and remote numbers (Jiri Olsa)
Fixes:
- Make sure errors aren't suppressed by the TUI reset at the end of
a 'perf c2c report' session (Jiri Olsa)
Infrastructure changes:
- Initial work on having the annotate code better support multiple
architectures, including the ability to cross-annotate, i.e. to
annotate perf.data files collected on an ARM system on a x86_64
workstation (Arnaldo Carvalho de Melo, Ravi Bangoria, Kim Phillips)
- Use USECS_PER_SEC instead of hard coded number in libtraceevent (Steven Rostedt)
- Add retrieval of preempt count and latency flags in libtraceevent (Steven Rostedt)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf/util/annotate.c')
-rw-r--r-- | tools/perf/util/annotate.c | 251 |
1 files changed, 127 insertions, 124 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index aeb5a441bd74..095d90a9077f 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -18,17 +18,61 @@ | |||
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; |
27 | static regex_t file_lineno; | 29 | static regex_t file_lineno; |
28 | 30 | ||
29 | static struct ins *ins__find(const char *name); | 31 | static struct ins *ins__find(struct arch *arch, 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 ins *instructions; | ||
37 | size_t nr_instructions; | ||
38 | bool sorted_instructions; | ||
39 | struct { | ||
40 | char comment_char; | ||
41 | char skip_functions_char; | ||
42 | } objdump; | ||
43 | }; | ||
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 | |||
56 | static struct arch architectures[] = { | ||
57 | { | ||
58 | .name = "arm", | ||
59 | .instructions = arm__instructions, | ||
60 | .nr_instructions = ARRAY_SIZE(arm__instructions), | ||
61 | .objdump = { | ||
62 | .comment_char = ';', | ||
63 | .skip_functions_char = '+', | ||
64 | }, | ||
65 | }, | ||
66 | { | ||
67 | .name = "x86", | ||
68 | .instructions = x86__instructions, | ||
69 | .nr_instructions = ARRAY_SIZE(x86__instructions), | ||
70 | .objdump = { | ||
71 | .comment_char = '#', | ||
72 | }, | ||
73 | }, | ||
74 | }; | ||
75 | |||
32 | static void ins__delete(struct ins_operands *ops) | 76 | static void ins__delete(struct ins_operands *ops) |
33 | { | 77 | { |
34 | if (ops == NULL) | 78 | if (ops == NULL) |
@@ -54,7 +98,7 @@ int ins__scnprintf(struct ins *ins, char *bf, size_t size, | |||
54 | return ins__raw_scnprintf(ins, bf, size, ops); | 98 | return ins__raw_scnprintf(ins, bf, size, ops); |
55 | } | 99 | } |
56 | 100 | ||
57 | static int call__parse(struct ins_operands *ops, struct map *map) | 101 | static int call__parse(struct arch *arch, struct ins_operands *ops, struct map *map) |
58 | { | 102 | { |
59 | char *endptr, *tok, *name; | 103 | char *endptr, *tok, *name; |
60 | 104 | ||
@@ -66,10 +110,9 @@ static int call__parse(struct ins_operands *ops, struct map *map) | |||
66 | 110 | ||
67 | name++; | 111 | name++; |
68 | 112 | ||
69 | #ifdef __arm__ | 113 | if (arch->objdump.skip_functions_char && |
70 | if (strchr(name, '+')) | 114 | strchr(name, arch->objdump.skip_functions_char)) |
71 | return -1; | 115 | return -1; |
72 | #endif | ||
73 | 116 | ||
74 | tok = strchr(name, '>'); | 117 | tok = strchr(name, '>'); |
75 | if (tok == NULL) | 118 | if (tok == NULL) |
@@ -118,7 +161,7 @@ bool ins__is_call(const struct ins *ins) | |||
118 | return ins->ops == &call_ops; | 161 | return ins->ops == &call_ops; |
119 | } | 162 | } |
120 | 163 | ||
121 | static int jump__parse(struct ins_operands *ops, struct map *map __maybe_unused) | 164 | static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map __maybe_unused) |
122 | { | 165 | { |
123 | const char *s = strchr(ops->raw, '+'); | 166 | const char *s = strchr(ops->raw, '+'); |
124 | 167 | ||
@@ -173,7 +216,7 @@ static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) | |||
173 | return 0; | 216 | return 0; |
174 | } | 217 | } |
175 | 218 | ||
176 | static int lock__parse(struct ins_operands *ops, struct map *map) | 219 | static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map *map) |
177 | { | 220 | { |
178 | char *name; | 221 | char *name; |
179 | 222 | ||
@@ -184,7 +227,7 @@ static int lock__parse(struct ins_operands *ops, struct map *map) | |||
184 | 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) |
185 | goto out_free_ops; | 228 | goto out_free_ops; |
186 | 229 | ||
187 | ops->locked.ins = ins__find(name); | 230 | ops->locked.ins = ins__find(arch, name); |
188 | free(name); | 231 | free(name); |
189 | 232 | ||
190 | if (ops->locked.ins == NULL) | 233 | if (ops->locked.ins == NULL) |
@@ -194,7 +237,7 @@ static int lock__parse(struct ins_operands *ops, struct map *map) | |||
194 | return 0; | 237 | return 0; |
195 | 238 | ||
196 | if (ops->locked.ins->ops->parse && | 239 | if (ops->locked.ins->ops->parse && |
197 | ops->locked.ins->ops->parse(ops->locked.ops, map) < 0) | 240 | ops->locked.ins->ops->parse(arch, ops->locked.ops, map) < 0) |
198 | goto out_free_ops; | 241 | goto out_free_ops; |
199 | 242 | ||
200 | return 0; | 243 | return 0; |
@@ -237,7 +280,7 @@ static struct ins_ops lock_ops = { | |||
237 | .scnprintf = lock__scnprintf, | 280 | .scnprintf = lock__scnprintf, |
238 | }; | 281 | }; |
239 | 282 | ||
240 | static int mov__parse(struct ins_operands *ops, struct map *map __maybe_unused) | 283 | static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map *map __maybe_unused) |
241 | { | 284 | { |
242 | char *s = strchr(ops->raw, ','), *target, *comment, prev; | 285 | char *s = strchr(ops->raw, ','), *target, *comment, prev; |
243 | 286 | ||
@@ -252,11 +295,7 @@ static int mov__parse(struct ins_operands *ops, struct map *map __maybe_unused) | |||
252 | return -1; | 295 | return -1; |
253 | 296 | ||
254 | target = ++s; | 297 | target = ++s; |
255 | #ifdef __arm__ | 298 | comment = strchr(s, arch->objdump.comment_char); |
256 | comment = strchr(s, ';'); | ||
257 | #else | ||
258 | comment = strchr(s, '#'); | ||
259 | #endif | ||
260 | 299 | ||
261 | if (comment != NULL) | 300 | if (comment != NULL) |
262 | s = comment - 1; | 301 | s = comment - 1; |
@@ -304,7 +343,7 @@ static struct ins_ops mov_ops = { | |||
304 | .scnprintf = mov__scnprintf, | 343 | .scnprintf = mov__scnprintf, |
305 | }; | 344 | }; |
306 | 345 | ||
307 | static int dec__parse(struct ins_operands *ops, struct map *map __maybe_unused) | 346 | static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map *map __maybe_unused) |
308 | { | 347 | { |
309 | char *target, *comment, *s, prev; | 348 | char *target, *comment, *s, prev; |
310 | 349 | ||
@@ -364,99 +403,6 @@ bool ins__is_ret(const struct ins *ins) | |||
364 | return ins->ops == &ret_ops; | 403 | return ins->ops == &ret_ops; |
365 | } | 404 | } |
366 | 405 | ||
367 | static struct ins instructions[] = { | ||
368 | { .name = "add", .ops = &mov_ops, }, | ||
369 | { .name = "addl", .ops = &mov_ops, }, | ||
370 | { .name = "addq", .ops = &mov_ops, }, | ||
371 | { .name = "addw", .ops = &mov_ops, }, | ||
372 | { .name = "and", .ops = &mov_ops, }, | ||
373 | #ifdef __arm__ | ||
374 | { .name = "b", .ops = &jump_ops, }, // might also be a call | ||
375 | { .name = "bcc", .ops = &jump_ops, }, | ||
376 | { .name = "bcs", .ops = &jump_ops, }, | ||
377 | { .name = "beq", .ops = &jump_ops, }, | ||
378 | { .name = "bge", .ops = &jump_ops, }, | ||
379 | { .name = "bgt", .ops = &jump_ops, }, | ||
380 | { .name = "bhi", .ops = &jump_ops, }, | ||
381 | { .name = "bl", .ops = &call_ops, }, | ||
382 | { .name = "bls", .ops = &jump_ops, }, | ||
383 | { .name = "blt", .ops = &jump_ops, }, | ||
384 | { .name = "blx", .ops = &call_ops, }, | ||
385 | { .name = "bne", .ops = &jump_ops, }, | ||
386 | #endif | ||
387 | { .name = "bts", .ops = &mov_ops, }, | ||
388 | { .name = "call", .ops = &call_ops, }, | ||
389 | { .name = "callq", .ops = &call_ops, }, | ||
390 | { .name = "cmp", .ops = &mov_ops, }, | ||
391 | { .name = "cmpb", .ops = &mov_ops, }, | ||
392 | { .name = "cmpl", .ops = &mov_ops, }, | ||
393 | { .name = "cmpq", .ops = &mov_ops, }, | ||
394 | { .name = "cmpw", .ops = &mov_ops, }, | ||
395 | { .name = "cmpxch", .ops = &mov_ops, }, | ||
396 | { .name = "dec", .ops = &dec_ops, }, | ||
397 | { .name = "decl", .ops = &dec_ops, }, | ||
398 | { .name = "imul", .ops = &mov_ops, }, | ||
399 | { .name = "inc", .ops = &dec_ops, }, | ||
400 | { .name = "incl", .ops = &dec_ops, }, | ||
401 | { .name = "ja", .ops = &jump_ops, }, | ||
402 | { .name = "jae", .ops = &jump_ops, }, | ||
403 | { .name = "jb", .ops = &jump_ops, }, | ||
404 | { .name = "jbe", .ops = &jump_ops, }, | ||
405 | { .name = "jc", .ops = &jump_ops, }, | ||
406 | { .name = "jcxz", .ops = &jump_ops, }, | ||
407 | { .name = "je", .ops = &jump_ops, }, | ||
408 | { .name = "jecxz", .ops = &jump_ops, }, | ||
409 | { .name = "jg", .ops = &jump_ops, }, | ||
410 | { .name = "jge", .ops = &jump_ops, }, | ||
411 | { .name = "jl", .ops = &jump_ops, }, | ||
412 | { .name = "jle", .ops = &jump_ops, }, | ||
413 | { .name = "jmp", .ops = &jump_ops, }, | ||
414 | { .name = "jmpq", .ops = &jump_ops, }, | ||
415 | { .name = "jna", .ops = &jump_ops, }, | ||
416 | { .name = "jnae", .ops = &jump_ops, }, | ||
417 | { .name = "jnb", .ops = &jump_ops, }, | ||
418 | { .name = "jnbe", .ops = &jump_ops, }, | ||
419 | { .name = "jnc", .ops = &jump_ops, }, | ||
420 | { .name = "jne", .ops = &jump_ops, }, | ||
421 | { .name = "jng", .ops = &jump_ops, }, | ||
422 | { .name = "jnge", .ops = &jump_ops, }, | ||
423 | { .name = "jnl", .ops = &jump_ops, }, | ||
424 | { .name = "jnle", .ops = &jump_ops, }, | ||
425 | { .name = "jno", .ops = &jump_ops, }, | ||
426 | { .name = "jnp", .ops = &jump_ops, }, | ||
427 | { .name = "jns", .ops = &jump_ops, }, | ||
428 | { .name = "jnz", .ops = &jump_ops, }, | ||
429 | { .name = "jo", .ops = &jump_ops, }, | ||
430 | { .name = "jp", .ops = &jump_ops, }, | ||
431 | { .name = "jpe", .ops = &jump_ops, }, | ||
432 | { .name = "jpo", .ops = &jump_ops, }, | ||
433 | { .name = "jrcxz", .ops = &jump_ops, }, | ||
434 | { .name = "js", .ops = &jump_ops, }, | ||
435 | { .name = "jz", .ops = &jump_ops, }, | ||
436 | { .name = "lea", .ops = &mov_ops, }, | ||
437 | { .name = "lock", .ops = &lock_ops, }, | ||
438 | { .name = "mov", .ops = &mov_ops, }, | ||
439 | { .name = "movb", .ops = &mov_ops, }, | ||
440 | { .name = "movdqa",.ops = &mov_ops, }, | ||
441 | { .name = "movl", .ops = &mov_ops, }, | ||
442 | { .name = "movq", .ops = &mov_ops, }, | ||
443 | { .name = "movslq", .ops = &mov_ops, }, | ||
444 | { .name = "movzbl", .ops = &mov_ops, }, | ||
445 | { .name = "movzwl", .ops = &mov_ops, }, | ||
446 | { .name = "nop", .ops = &nop_ops, }, | ||
447 | { .name = "nopl", .ops = &nop_ops, }, | ||
448 | { .name = "nopw", .ops = &nop_ops, }, | ||
449 | { .name = "or", .ops = &mov_ops, }, | ||
450 | { .name = "orl", .ops = &mov_ops, }, | ||
451 | { .name = "test", .ops = &mov_ops, }, | ||
452 | { .name = "testb", .ops = &mov_ops, }, | ||
453 | { .name = "testl", .ops = &mov_ops, }, | ||
454 | { .name = "xadd", .ops = &mov_ops, }, | ||
455 | { .name = "xbeginl", .ops = &jump_ops, }, | ||
456 | { .name = "xbeginq", .ops = &jump_ops, }, | ||
457 | { .name = "retq", .ops = &ret_ops, }, | ||
458 | }; | ||
459 | |||
460 | static int ins__key_cmp(const void *name, const void *insp) | 406 | static int ins__key_cmp(const void *name, const void *insp) |
461 | { | 407 | { |
462 | const struct ins *ins = insp; | 408 | const struct ins *ins = insp; |
@@ -472,24 +418,58 @@ static int ins__cmp(const void *a, const void *b) | |||
472 | return strcmp(ia->name, ib->name); | 418 | return strcmp(ia->name, ib->name); |
473 | } | 419 | } |
474 | 420 | ||
475 | static void ins__sort(void) | 421 | static void ins__sort(struct arch *arch) |
476 | { | 422 | { |
477 | const int nmemb = ARRAY_SIZE(instructions); | 423 | const int nmemb = arch->nr_instructions; |
478 | 424 | ||
479 | qsort(instructions, nmemb, sizeof(struct ins), ins__cmp); | 425 | qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp); |
480 | } | 426 | } |
481 | 427 | ||
482 | static struct ins *ins__find(const char *name) | 428 | static struct ins *ins__find(struct arch *arch, const char *name) |
483 | { | 429 | { |
484 | const int nmemb = ARRAY_SIZE(instructions); | 430 | const int nmemb = arch->nr_instructions; |
431 | |||
432 | if (!arch->sorted_instructions) { | ||
433 | ins__sort(arch); | ||
434 | arch->sorted_instructions = true; | ||
435 | } | ||
436 | |||
437 | return bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp); | ||
438 | } | ||
439 | |||
440 | static int arch__key_cmp(const void *name, const void *archp) | ||
441 | { | ||
442 | const struct arch *arch = archp; | ||
443 | |||
444 | return strcmp(name, arch->name); | ||
445 | } | ||
446 | |||
447 | static int arch__cmp(const void *a, const void *b) | ||
448 | { | ||
449 | const struct arch *aa = a; | ||
450 | const struct arch *ab = b; | ||
451 | |||
452 | return strcmp(aa->name, ab->name); | ||
453 | } | ||
454 | |||
455 | static void arch__sort(void) | ||
456 | { | ||
457 | const int nmemb = ARRAY_SIZE(architectures); | ||
458 | |||
459 | qsort(architectures, nmemb, sizeof(struct arch), arch__cmp); | ||
460 | } | ||
461 | |||
462 | static struct arch *arch__find(const char *name) | ||
463 | { | ||
464 | const int nmemb = ARRAY_SIZE(architectures); | ||
485 | static bool sorted; | 465 | static bool sorted; |
486 | 466 | ||
487 | if (!sorted) { | 467 | if (!sorted) { |
488 | ins__sort(); | 468 | arch__sort(); |
489 | sorted = true; | 469 | sorted = true; |
490 | } | 470 | } |
491 | 471 | ||
492 | return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp); | 472 | return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp); |
493 | } | 473 | } |
494 | 474 | ||
495 | int symbol__alloc_hist(struct symbol *sym) | 475 | int symbol__alloc_hist(struct symbol *sym) |
@@ -709,9 +689,9 @@ 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); | 689 | return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); |
710 | } | 690 | } |
711 | 691 | ||
712 | static void disasm_line__init_ins(struct disasm_line *dl, struct map *map) | 692 | static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map *map) |
713 | { | 693 | { |
714 | dl->ins = ins__find(dl->name); | 694 | dl->ins = ins__find(arch, dl->name); |
715 | 695 | ||
716 | if (dl->ins == NULL) | 696 | if (dl->ins == NULL) |
717 | return; | 697 | return; |
@@ -719,7 +699,7 @@ static void disasm_line__init_ins(struct disasm_line *dl, struct map *map) | |||
719 | if (!dl->ins->ops) | 699 | if (!dl->ins->ops) |
720 | return; | 700 | return; |
721 | 701 | ||
722 | if (dl->ins->ops->parse && dl->ins->ops->parse(&dl->ops, map) < 0) | 702 | if (dl->ins->ops->parse && dl->ins->ops->parse(arch, &dl->ops, map) < 0) |
723 | dl->ins = NULL; | 703 | dl->ins = NULL; |
724 | } | 704 | } |
725 | 705 | ||
@@ -762,6 +742,7 @@ out_free_name: | |||
762 | 742 | ||
763 | static struct disasm_line *disasm_line__new(s64 offset, char *line, | 743 | static struct disasm_line *disasm_line__new(s64 offset, char *line, |
764 | size_t privsize, int line_nr, | 744 | size_t privsize, int line_nr, |
745 | struct arch *arch, | ||
765 | struct map *map) | 746 | struct map *map) |
766 | { | 747 | { |
767 | struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); | 748 | struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); |
@@ -777,7 +758,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) | 758 | if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0) |
778 | goto out_free_line; | 759 | goto out_free_line; |
779 | 760 | ||
780 | disasm_line__init_ins(dl, map); | 761 | disasm_line__init_ins(dl, arch, map); |
781 | } | 762 | } |
782 | } | 763 | } |
783 | 764 | ||
@@ -1087,6 +1068,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. | 1068 | * The ops.raw part will be parsed further according to type of the instruction. |
1088 | */ | 1069 | */ |
1089 | static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | 1070 | static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, |
1071 | struct arch *arch, | ||
1090 | FILE *file, size_t privsize, | 1072 | FILE *file, size_t privsize, |
1091 | int *line_nr) | 1073 | int *line_nr) |
1092 | { | 1074 | { |
@@ -1149,7 +1131,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | |||
1149 | parsed_line = tmp2 + 1; | 1131 | parsed_line = tmp2 + 1; |
1150 | } | 1132 | } |
1151 | 1133 | ||
1152 | dl = disasm_line__new(offset, parsed_line, privsize, *line_nr, map); | 1134 | dl = disasm_line__new(offset, parsed_line, privsize, *line_nr, arch, map); |
1153 | free(line); | 1135 | free(line); |
1154 | (*line_nr)++; | 1136 | (*line_nr)++; |
1155 | 1137 | ||
@@ -1280,10 +1262,23 @@ fallback: | |||
1280 | return 0; | 1262 | return 0; |
1281 | } | 1263 | } |
1282 | 1264 | ||
1283 | int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize) | 1265 | static const char *annotate__norm_arch(const char *arch_name) |
1266 | { | ||
1267 | struct utsname uts; | ||
1268 | |||
1269 | if (!arch_name) { /* Assume we are annotating locally. */ | ||
1270 | if (uname(&uts) < 0) | ||
1271 | return NULL; | ||
1272 | arch_name = uts.machine; | ||
1273 | } | ||
1274 | return normalize_arch((char *)arch_name); | ||
1275 | } | ||
1276 | |||
1277 | int symbol__disassemble(struct symbol *sym, struct map *map, const char *arch_name, size_t privsize) | ||
1284 | { | 1278 | { |
1285 | struct dso *dso = map->dso; | 1279 | struct dso *dso = map->dso; |
1286 | char command[PATH_MAX * 2]; | 1280 | char command[PATH_MAX * 2]; |
1281 | struct arch *arch = NULL; | ||
1287 | FILE *file; | 1282 | FILE *file; |
1288 | char symfs_filename[PATH_MAX]; | 1283 | char symfs_filename[PATH_MAX]; |
1289 | struct kcore_extract kce; | 1284 | struct kcore_extract kce; |
@@ -1297,6 +1292,14 @@ int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize) | |||
1297 | if (err) | 1292 | if (err) |
1298 | return err; | 1293 | return err; |
1299 | 1294 | ||
1295 | arch_name = annotate__norm_arch(arch_name); | ||
1296 | if (!arch_name) | ||
1297 | return -1; | ||
1298 | |||
1299 | arch = arch__find(arch_name); | ||
1300 | if (arch == NULL) | ||
1301 | return -ENOTSUP; | ||
1302 | |||
1300 | pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, | 1303 | pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, |
1301 | symfs_filename, sym->name, map->unmap_ip(map, sym->start), | 1304 | symfs_filename, sym->name, map->unmap_ip(map, sym->start), |
1302 | map->unmap_ip(map, sym->end)); | 1305 | map->unmap_ip(map, sym->end)); |
@@ -1395,7 +1398,7 @@ int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize) | |||
1395 | 1398 | ||
1396 | nline = 0; | 1399 | nline = 0; |
1397 | while (!feof(file)) { | 1400 | while (!feof(file)) { |
1398 | if (symbol__parse_objdump_line(sym, map, file, privsize, | 1401 | if (symbol__parse_objdump_line(sym, map, arch, file, privsize, |
1399 | &lineno) < 0) | 1402 | &lineno) < 0) |
1400 | break; | 1403 | break; |
1401 | nline++; | 1404 | nline++; |
@@ -1793,7 +1796,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, | |||
1793 | struct rb_root source_line = RB_ROOT; | 1796 | struct rb_root source_line = RB_ROOT; |
1794 | u64 len; | 1797 | u64 len; |
1795 | 1798 | ||
1796 | if (symbol__disassemble(sym, map, 0) < 0) | 1799 | if (symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), 0) < 0) |
1797 | return -1; | 1800 | return -1; |
1798 | 1801 | ||
1799 | len = symbol__size(sym); | 1802 | len = symbol__size(sym); |