From 29ed6e76b4ca81103f31c8316f9e4cfcf134572f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 15 Apr 2012 15:24:39 -0300 Subject: perf annotate: Rename objdump_line to disasm_line We want to move away from using 'objdump -dS' as the only disassembler supported. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-lsn9pjuxxm5ezsubyhkmprw7@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'tools/perf/util/annotate.h') diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index efa5dc82bfa..8bb68bb2a04 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -7,15 +7,14 @@ #include #include -struct objdump_line { +struct disasm_line { struct list_head node; s64 offset; char *line; }; -void objdump_line__free(struct objdump_line *self); -struct objdump_line *objdump__get_next_ip_line(struct list_head *head, - struct objdump_line *pos); +void disasm_line__free(struct disasm_line *dl); +struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); struct sym_hist { u64 sum; @@ -32,7 +31,7 @@ struct source_line { * * @histogram: Array of addr hit histograms per event being monitored * @lines: If 'print_lines' is specified, per source code line percentages - * @source: source parsed from objdump -dS + * @source: source parsed from a disassembler like objdump -dS * * lines is allocated, percentages calculated and all sorted by percentage * when the annotation is about to be presented, so the percentages are for @@ -82,7 +81,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, int context); void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); -void objdump_line_list__purge(struct list_head *head); +void disasm__purge(struct list_head *head); int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, bool print_lines, bool full_paths, int min_pcnt, -- cgit v1.2.3-70-g09d2 From 5145418b06fa907883ff1f62301d534a0d26ba18 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 15 Apr 2012 15:52:18 -0300 Subject: perf annotate: Parse instruction For lines with instructions find the name and operands, breaking those tokens for consumption by the browser. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-6aazb9f5o3d9zi28e6rruv12@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 65 +++++++++++++++++++++++++++++++++++++++++++++- tools/perf/util/annotate.h | 3 +++ 2 files changed, 67 insertions(+), 1 deletion(-) (limited to 'tools/perf/util/annotate.h') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ef1d57def76..a72585ab52e 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -80,16 +80,50 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) { - struct disasm_line *dl = malloc(sizeof(*dl) + privsize); + struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); if (dl != NULL) { dl->offset = offset; dl->line = strdup(line); if (dl->line == NULL) goto out_delete; + + if (offset != -1) { + char *name = dl->line, tmp; + + while (isspace(name[0])) + ++name; + + if (name[0] == '\0') + goto out_delete; + + dl->operands = name + 1; + + while (dl->operands[0] != '\0' && + !isspace(dl->operands[0])) + ++dl->operands; + + tmp = dl->operands[0]; + dl->operands[0] = '\0'; + dl->name = strdup(name); + + if (dl->name == NULL) + goto out_free_line; + + dl->operands[0] = tmp; + + if (dl->operands[0] != '\0') { + dl->operands++; + while (isspace(dl->operands[0])) + ++dl->operands; + } + } } return dl; + +out_free_line: + free(dl->line); out_delete: free(dl); return NULL; @@ -98,6 +132,7 @@ out_delete: void disasm_line__free(struct disasm_line *dl) { free(dl->line); + free(dl->name); free(dl); } @@ -591,6 +626,34 @@ void disasm__purge(struct list_head *head) } } +static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp) +{ + size_t printed; + + if (dl->offset == -1) + return fprintf(fp, "%s\n", dl->line); + + printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name); + + if (dl->operands[0] != '\0') { + printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ", + dl->operands); + } + + return printed + fprintf(fp, "\n"); +} + +size_t disasm__fprintf(struct list_head *head, FILE *fp) +{ + struct disasm_line *pos; + size_t printed = 0; + + list_for_each_entry(pos, head, node) + printed += disasm_line__fprintf(pos, fp); + + return printed; +} + int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, bool print_lines, bool full_paths, int min_pcnt, int max_lines) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 8bb68bb2a04..dd7636d2413 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -11,10 +11,13 @@ struct disasm_line { struct list_head node; s64 offset; char *line; + char *name; + char *operands; }; void disasm_line__free(struct disasm_line *dl); struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); +size_t disasm__fprintf(struct list_head *head, FILE *fp); struct sym_hist { u64 sum; -- cgit v1.2.3-70-g09d2 From 4f9d03251b9d202ebce805757360ef0fac5eb74e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 18 Apr 2012 13:58:34 -0300 Subject: perf annotate: Disassembler instruction parsing So that at disassembly time we parse targets, etc. Supporting jump instructions initially, call functions are next. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-7vzlh66n5or46n27ji658cnl@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 19 ++---------- tools/perf/util/annotate.c | 63 +++++++++++++++++++++++++++++++++++++++ tools/perf/util/annotate.h | 13 ++++++++ 3 files changed, 79 insertions(+), 16 deletions(-) (limited to 'tools/perf/util/annotate.h') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 0bc3e652b54..bdbb54fd05a 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -315,26 +315,13 @@ struct disasm_line *annotate_browser__find_offset(struct annotate_browser *brows static bool annotate_browser__jump(struct annotate_browser *browser) { - const char *jumps[] = { "je", "jne", "ja", "jmpq", "js", "jmp", NULL }; struct disasm_line *dl = browser->selection; - s64 idx, offset; - char *s; - int i = 0; - - while (jumps[i] && strcmp(dl->name, jumps[i])) - ++i; + s64 idx; - if (jumps[i] == NULL) + if (!dl->ins || !ins__is_jump(dl->ins)) return false; - s = strchr(dl->operands, '+'); - if (s++ == NULL) { - ui_helpline__puts("Invallid jump instruction."); - return true; - } - - offset = strtoll(s, NULL, 16); - dl = annotate_browser__find_offset(browser, offset, &idx); + dl = annotate_browser__find_offset(browser, dl->target, &idx); if (dl == NULL) { ui_helpline__puts("Invallid jump offset"); return true; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a72585ab52e..4ee2c07924b 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -18,6 +18,53 @@ const char *disassembler_style; +static int jump_ops__parse_target(const char *operands, u64 *target) +{ + const char *s = strchr(operands, '+'); + + if (s++ == NULL) + return -1; + + *target = strtoll(s, NULL, 16); + return 0; +} + +static struct ins_ops jump_ops = { + .parse_target = jump_ops__parse_target, +}; + +bool ins__is_jump(const struct ins *ins) +{ + return ins->ops == &jump_ops; +} + + +/* + * Must be sorted by name! + */ +static struct ins instructions[] = { + { .name = "ja", .ops = &jump_ops, }, + { .name = "je", .ops = &jump_ops, }, + { .name = "jmp", .ops = &jump_ops, }, + { .name = "jmpq", .ops = &jump_ops, }, + { .name = "jne", .ops = &jump_ops, }, + { .name = "js", .ops = &jump_ops, }, +}; + +static int ins__cmp(const void *name, const void *insp) +{ + const struct ins *ins = insp; + + return strcmp(name, ins->name); +} + +static struct ins *ins__find(const char *name) +{ + const int nmemb = ARRAY_SIZE(instructions); + + return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp); +} + int symbol__annotate_init(struct map *map __used, struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); @@ -78,6 +125,20 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, return 0; } +static void disasm_line__init_ins(struct disasm_line *dl) +{ + dl->ins = ins__find(dl->name); + + if (dl->ins == NULL) + return; + + if (!dl->ins->ops) + return; + + if (dl->ins->ops->parse_target) + dl->ins->ops->parse_target(dl->operands, &dl->target); +} + static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) { struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); @@ -117,6 +178,8 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privs while (isspace(dl->operands[0])) ++dl->operands; } + + disasm_line__init_ins(dl); } } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index dd7636d2413..934c6fe3a91 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -7,11 +7,24 @@ #include #include +struct ins_ops { + int (*parse_target)(const char *operands, u64 *target); +}; + +struct ins { + const char *name; + struct ins_ops *ops; +}; + +bool ins__is_jump(const struct ins *ins); + struct disasm_line { struct list_head node; s64 offset; + u64 target; char *line; char *name; + struct ins *ins; char *operands; }; -- cgit v1.2.3-70-g09d2 From d86b0597c4bd41ea3edc6446a855306eed34f93b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 18 Apr 2012 16:07:38 -0300 Subject: perf annotate: Parse call targets earlier No need to do it everytime the user presses enter/-> on a call instruction. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-ybgss44m5ycry8mk7b1qdbre@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 10 +++++----- tools/perf/util/annotate.c | 18 +++++++++++++++++- tools/perf/util/annotate.h | 1 + 3 files changed, 23 insertions(+), 6 deletions(-) (limited to 'tools/perf/util/annotate.h') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index bdbb54fd05a..46ef966ccc5 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -266,11 +266,10 @@ static bool annotate_browser__callq(struct annotate_browser *browser, struct symbol *target; u64 ip; - if (strcmp(dl->name, "callq")) + if (!ins__is_call(dl->ins)) return false; - ip = strtoull(dl->operands, NULL, 16); - ip = ms->map->map_ip(ms->map, ip); + ip = ms->map->map_ip(ms->map, dl->target); target = map__find_symbol(ms->map, ip, NULL); if (target == NULL) { ui_helpline__puts("The called function was not found."); @@ -318,7 +317,7 @@ static bool annotate_browser__jump(struct annotate_browser *browser) struct disasm_line *dl = browser->selection; s64 idx; - if (!dl->ins || !ins__is_jump(dl->ins)) + if (!ins__is_jump(dl->ins)) return false; dl = annotate_browser__find_offset(browser, dl->target, &idx); @@ -556,7 +555,8 @@ show_help: ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); else if (self->selection->offset == -1) ui_helpline__puts("Actions are only available for assembly lines."); - else if (!(annotate_browser__jump(self) || + else if (!self->selection->ins || + !(annotate_browser__jump(self) || annotate_browser__callq(self, evidx, timer, arg, delay_secs))) ui_helpline__puts("Actions are only available for the 'callq' and jump instructions."); continue; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 4ee2c07924b..a4296fdd9a6 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -18,6 +18,21 @@ const char *disassembler_style; +static int call_ops__parse_target(const char *operands, u64 *target) +{ + *target = strtoull(operands, NULL, 16); + return 0; +} + +static struct ins_ops call_ops = { + .parse_target = call_ops__parse_target, +}; + +bool ins__is_call(const struct ins *ins) +{ + return ins->ops == &call_ops; +} + static int jump_ops__parse_target(const char *operands, u64 *target) { const char *s = strchr(operands, '+'); @@ -38,11 +53,12 @@ bool ins__is_jump(const struct ins *ins) return ins->ops == &jump_ops; } - /* * Must be sorted by name! */ static struct ins instructions[] = { + { .name = "call", .ops = &call_ops, }, + { .name = "callq", .ops = &call_ops, }, { .name = "ja", .ops = &jump_ops, }, { .name = "je", .ops = &jump_ops, }, { .name = "jmp", .ops = &jump_ops, }, diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 934c6fe3a91..a2105f204a4 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -17,6 +17,7 @@ struct ins { }; bool ins__is_jump(const struct ins *ins); +bool ins__is_call(const struct ins *ins); struct disasm_line { struct list_head node; -- cgit v1.2.3-70-g09d2 From 28548d78ad521310f0ae58f791aa796d3d685151 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Apr 2012 10:16:27 -0300 Subject: perf annotate: Introduce scnprintf ins_ops method And implement the jump one, where if the operands string is not passed, a compact form that uses just the target address is used. Right now this is toggled via the 'o' option in the annotate browser, switching from: 0.00 : ffffffff811661e8: je ffffffff81166204 0.00 : ffffffff811661ea: cmp $0xb,%esi 0.00 : ffffffff811661ed: je ffffffff811661f8 To: 0.00 : 28: je 44 0.00 : 2a: cmp $0xb,%esi 0.00 : 2d: je 38 Suggested-by: Linus Torvalds Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-o88q46yh4kxgpd1chk5gvjl5@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 13 +++++++++++-- tools/perf/util/annotate.c | 10 ++++++++++ tools/perf/util/annotate.h | 4 ++++ 3 files changed, 25 insertions(+), 2 deletions(-) (limited to 'tools/perf/util/annotate.h') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 46ef966ccc5..f7d2db3e846 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -83,7 +83,7 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro else if (dl->offset == -1) slsmg_write_nstring(dl->line, width - 18); else { - char bf[64]; + char bf[256], *line = dl->line; u64 addr = dl->offset; int printed, color = -1; @@ -96,7 +96,16 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro slsmg_write_nstring(bf, printed); if (change_color) ui_browser__set_color(self, color); - slsmg_write_nstring(dl->line, width - 18 - printed); + if (dl->ins && dl->ins->ops->scnprintf) { + dl->ins->ops->scnprintf(dl->ins, bf, sizeof(bf), + !ab->use_offset ? dl->operands : NULL, + dl->target); + line = bf; + slsmg_write_nstring(" ", 7); + printed += 7; + } + + slsmg_write_nstring(line, width - 18 - printed); } if (current_entry) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a4296fdd9a6..ed1f89d7044 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -44,8 +44,18 @@ static int jump_ops__parse_target(const char *operands, u64 *target) return 0; } +static int jump_ops__scnprintf(struct ins *ins, char *bf, size_t size, + const char *operands, u64 target) +{ + if (operands) + return scnprintf(bf, size, "%-6.6s %s", ins->name, operands); + + return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, target); +} + static struct ins_ops jump_ops = { .parse_target = jump_ops__parse_target, + .scnprintf = jump_ops__scnprintf, }; bool ins__is_jump(const struct ins *ins) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index a2105f204a4..6314335007f 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -7,8 +7,12 @@ #include #include +struct ins; + struct ins_ops { int (*parse_target)(const char *operands, u64 *target); + int (*scnprintf)(struct ins *ins, char *bf, size_t size, + const char *operands, u64 target); }; struct ins { -- cgit v1.2.3-70-g09d2 From c7e6ead7347813b5833efb9b32908c08ff131259 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 20 Apr 2012 14:38:46 -0300 Subject: perf annotate: Group operands members So that the ins_ops can handle them in a single place, instead of adding more and more functions or ins_ops parameters. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-pk4dqaum6ftiz104dvimwgtb@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 17 ++++++------ tools/perf/util/annotate.c | 56 +++++++++++++++++++-------------------- tools/perf/util/annotate.h | 22 ++++++++------- 3 files changed, 49 insertions(+), 46 deletions(-) (limited to 'tools/perf/util/annotate.h') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index e760326efca..9c7b6d87822 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -113,13 +113,12 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro if (change_color) ui_browser__set_color(self, color); if (dl->ins && dl->ins->ops->scnprintf) { - dl->ins->ops->scnprintf(dl->ins, bf, sizeof(bf), - !ab->use_offset ? dl->operands : NULL, - dl->target); + dl->ins->ops->scnprintf(dl->ins, bf, sizeof(bf), &dl->ops, + !ab->use_offset); slsmg_write_nstring(" ", 2); printed += 2; } else - scnprintf(bf, sizeof(bf), " %-6.6s %s", dl->name, dl->operands); + scnprintf(bf, sizeof(bf), " %-6.6s %s", dl->name, dl->ops.raw); slsmg_write_nstring(bf, width - 10 - printed); } @@ -294,7 +293,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, if (!ins__is_call(dl->ins)) return false; - ip = ms->map->map_ip(ms->map, dl->target); + ip = ms->map->map_ip(ms->map, dl->ops.target); target = map__find_symbol(ms->map, ip, NULL); if (target == NULL) { ui_helpline__puts("The called function was not found."); @@ -345,7 +344,7 @@ static bool annotate_browser__jump(struct annotate_browser *browser) if (!ins__is_jump(dl->ins)) return false; - dl = annotate_browser__find_offset(browser, dl->target, &idx); + dl = annotate_browser__find_offset(browser, dl->ops.target, &idx); if (dl == NULL) { ui_helpline__puts("Invallid jump offset"); return true; @@ -621,14 +620,14 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser if (!dl || !dl->ins || !ins__is_jump(dl->ins)) continue; - if (dl->target >= size) { + if (dl->ops.target >= size) { ui__error("jump to after symbol!\n" "size: %zx, jump target: %" PRIx64, - size, dl->target); + size, dl->ops.target); continue; } - dlt = browser->offsets[dl->target]; + dlt = browser->offsets[dl->ops.target]; bdlt = disasm_line__browser(dlt); bdlt->jump_target = true; } diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index e70cbb4f3be..7f6c14b3fd7 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -18,14 +18,14 @@ const char *disassembler_style; -static int call_ops__parse_target(const char *operands, u64 *target) +static int call__parse(struct ins_operands *ops) { - *target = strtoull(operands, NULL, 16); + ops->target = strtoull(ops->raw, NULL, 16); return 0; } static struct ins_ops call_ops = { - .parse_target = call_ops__parse_target, + .parse = call__parse, }; bool ins__is_call(const struct ins *ins) @@ -33,29 +33,29 @@ bool ins__is_call(const struct ins *ins) return ins->ops == &call_ops; } -static int jump_ops__parse_target(const char *operands, u64 *target) +static int jump__parse(struct ins_operands *ops) { - const char *s = strchr(operands, '+'); + const char *s = strchr(ops->raw, '+'); if (s++ == NULL) return -1; - *target = strtoll(s, NULL, 16); + ops->target = strtoll(s, NULL, 16); return 0; } -static int jump_ops__scnprintf(struct ins *ins, char *bf, size_t size, - const char *operands, u64 target) +static int jump__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, bool addrs) { - if (operands) - return scnprintf(bf, size, "%-6.6s %s", ins->name, operands); + if (addrs) + return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw); - return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, target); + return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target); } static struct ins_ops jump_ops = { - .parse_target = jump_ops__parse_target, - .scnprintf = jump_ops__scnprintf, + .parse = jump__parse, + .scnprintf = jump__scnprintf, }; bool ins__is_jump(const struct ins *ins) @@ -190,8 +190,8 @@ static void disasm_line__init_ins(struct disasm_line *dl) if (!dl->ins->ops) return; - if (dl->ins->ops->parse_target) - dl->ins->ops->parse_target(dl->operands, &dl->target); + if (dl->ins->ops->parse) + dl->ins->ops->parse(&dl->ops); } static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) @@ -213,25 +213,25 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privs if (name[0] == '\0') goto out_delete; - dl->operands = name + 1; + dl->ops.raw = name + 1; - while (dl->operands[0] != '\0' && - !isspace(dl->operands[0])) - ++dl->operands; + while (dl->ops.raw[0] != '\0' && + !isspace(dl->ops.raw[0])) + ++dl->ops.raw; - tmp = dl->operands[0]; - dl->operands[0] = '\0'; + tmp = dl->ops.raw[0]; + dl->ops.raw[0] = '\0'; dl->name = strdup(name); if (dl->name == NULL) goto out_free_line; - dl->operands[0] = tmp; + dl->ops.raw[0] = tmp; - if (dl->operands[0] != '\0') { - dl->operands++; - while (isspace(dl->operands[0])) - ++dl->operands; + if (dl->ops.raw[0] != '\0') { + dl->ops.raw++; + while (isspace(dl->ops.raw[0])) + ++dl->ops.raw; } disasm_line__init_ins(dl); @@ -753,9 +753,9 @@ static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp) printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name); - if (dl->operands[0] != '\0') { + if (dl->ops.raw[0] != '\0') { printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ", - dl->operands); + dl->ops.raw); } return printed + fprintf(fp, "\n"); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 6314335007f..a6f60d5c513 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -9,10 +9,15 @@ struct ins; +struct ins_operands { + char *raw; + u64 target; +}; + struct ins_ops { - int (*parse_target)(const char *operands, u64 *target); + int (*parse)(struct ins_operands *ops); int (*scnprintf)(struct ins *ins, char *bf, size_t size, - const char *operands, u64 target); + struct ins_operands *ops, bool addrs); }; struct ins { @@ -24,13 +29,12 @@ bool ins__is_jump(const struct ins *ins); bool ins__is_call(const struct ins *ins); struct disasm_line { - struct list_head node; - s64 offset; - u64 target; - char *line; - char *name; - struct ins *ins; - char *operands; + struct list_head node; + s64 offset; + char *line; + char *name; + struct ins *ins; + struct ins_operands ops; }; void disasm_line__free(struct disasm_line *dl); -- cgit v1.2.3-70-g09d2 From d22328855666464731ee95d9e1e8d35dc7a39d8d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 20 Apr 2012 15:26:47 -0300 Subject: perf annotate browser: Suppress the callq address 0.00 | callq ffffffff8112f190 <__mod_zone_page_state> Becomes: 0.00 | callq __mod_zone_page_state But if you press 'o' it gets verbose, i.e. as in objdump -dS: 0.00 | ffffffff8116bdda: callq ffffffff8112f190 <__mod_zone_page_state> Requested-by: Linus Torvalds Cc: David Ahern Cc: Frederic Weisbecker Cc: Linus Torvalds Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-bwse2wib954y0db7dq91bes5@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 43 +++++++++++++++++++++++++++++++++++++++++-- tools/perf/util/annotate.h | 1 + 2 files changed, 42 insertions(+), 2 deletions(-) (limited to 'tools/perf/util/annotate.h') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 7f6c14b3fd7..b07d7d1425f 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -20,12 +20,50 @@ const char *disassembler_style; static int call__parse(struct ins_operands *ops) { - ops->target = strtoull(ops->raw, NULL, 16); + char *endptr, *tok, *name; + + ops->target = strtoull(ops->raw, &endptr, 16); + + name = strchr(endptr, '<'); + if (name == NULL) + goto indirect_call; + + name++; + + tok = strchr(name, '>'); + if (tok == NULL) + return -1; + + *tok = '\0'; + ops->target_name = strdup(name); + *tok = '>'; + + return ops->target_name == NULL ? -1 : 0; + +indirect_call: + tok = strchr(endptr, '*'); + if (tok == NULL) + return -1; + + ops->target = strtoull(tok + 1, NULL, 16); return 0; } +static int call__scnprintf(struct ins *ins, char *bf, size_t size, + struct ins_operands *ops, bool addrs) +{ + if (addrs) + return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw); + + if (ops->target_name) + return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target_name); + + return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target); +} + static struct ins_ops call_ops = { - .parse = call__parse, + .parse = call__parse, + .scnprintf = call__scnprintf, }; bool ins__is_call(const struct ins *ins) @@ -251,6 +289,7 @@ void disasm_line__free(struct disasm_line *dl) { free(dl->line); free(dl->name); + free(dl->ops.target_name); free(dl); } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index a6f60d5c513..8a8af0d82b0 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -11,6 +11,7 @@ struct ins; struct ins_operands { char *raw; + char *target_name; u64 target; }; -- cgit v1.2.3-70-g09d2 From 44d1a3edfbd65f9da6725921e2425b10477772d8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 25 Apr 2012 08:00:23 -0300 Subject: perf annotate: Disambiguage offsets and addresses in operands We were using ins_ops->target for callq addresses and jump offsets, disambiguate by having ins_ops->target.addr and ins_ops->target.offset. For jumps we'll need both to fixup lines that don't have an offset on the <> part. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-3nlcmstua75u07ao7wja1rwx@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 14 +++++++------- tools/perf/util/annotate.c | 20 ++++++++++---------- tools/perf/util/annotate.h | 7 +++++-- 3 files changed, 22 insertions(+), 19 deletions(-) (limited to 'tools/perf/util/annotate.h') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 4c83fe3d7da..73e1ef0081d 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -112,7 +112,7 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro ui_browser__set_color(self, color); if (dl->ins && dl->ins->ops->scnprintf) { if (ins__is_jump(dl->ins)) { - bool fwd = dl->ops.target > (u64)dl->offset; + bool fwd = dl->ops.target.offset > (u64)dl->offset; ui_browser__write_graph(self, fwd ? SLSMG_DARROW_CHAR : SLSMG_UARROW_CHAR); @@ -156,7 +156,7 @@ static void annotate_browser__draw_current_loop(struct ui_browser *browser) if (!pos->ins || !ins__is_jump(pos->ins)) continue; - target = ab->offsets[pos->ops.target]; + target = ab->offsets[pos->ops.target.offset]; if (!target) continue; @@ -360,7 +360,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, if (!ins__is_call(dl->ins)) return false; - ip = ms->map->map_ip(ms->map, dl->ops.target); + ip = ms->map->map_ip(ms->map, dl->ops.target.addr); target = map__find_symbol(ms->map, ip, NULL); if (target == NULL) { ui_helpline__puts("The called function was not found."); @@ -411,7 +411,7 @@ static bool annotate_browser__jump(struct annotate_browser *browser) if (!ins__is_jump(dl->ins)) return false; - dl = annotate_browser__find_offset(browser, dl->ops.target, &idx); + dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx); if (dl == NULL) { ui_helpline__puts("Invallid jump offset"); return true; @@ -692,14 +692,14 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser if (!dl || !dl->ins || !ins__is_jump(dl->ins)) continue; - if (dl->ops.target >= size) { + if (dl->ops.target.offset >= size) { ui__error("jump to after symbol!\n" "size: %zx, jump target: %" PRIx64, - size, dl->ops.target); + size, dl->ops.target.offset); continue; } - dlt = browser->offsets[dl->ops.target]; + dlt = browser->offsets[dl->ops.target.offset]; /* * FIXME: Oops, no jump target? Buggy disassembler? Or do we * have to adjust to the previous offset? diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index b07d7d1425f..e1e7d0eb614 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -22,7 +22,7 @@ static int call__parse(struct ins_operands *ops) { char *endptr, *tok, *name; - ops->target = strtoull(ops->raw, &endptr, 16); + ops->target.addr = strtoull(ops->raw, &endptr, 16); name = strchr(endptr, '<'); if (name == NULL) @@ -35,17 +35,17 @@ static int call__parse(struct ins_operands *ops) return -1; *tok = '\0'; - ops->target_name = strdup(name); + ops->target.name = strdup(name); *tok = '>'; - return ops->target_name == NULL ? -1 : 0; + return ops->target.name == NULL ? -1 : 0; indirect_call: tok = strchr(endptr, '*'); if (tok == NULL) return -1; - ops->target = strtoull(tok + 1, NULL, 16); + ops->target.addr = strtoull(tok + 1, NULL, 16); return 0; } @@ -55,10 +55,10 @@ static int call__scnprintf(struct ins *ins, char *bf, size_t size, if (addrs) return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw); - if (ops->target_name) - return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target_name); + if (ops->target.name) + return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name); - return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target); + return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr); } static struct ins_ops call_ops = { @@ -78,7 +78,7 @@ static int jump__parse(struct ins_operands *ops) if (s++ == NULL) return -1; - ops->target = strtoll(s, NULL, 16); + ops->target.offset = strtoll(s, NULL, 16); return 0; } @@ -88,7 +88,7 @@ static int jump__scnprintf(struct ins *ins, char *bf, size_t size, if (addrs) return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw); - return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target); + return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset); } static struct ins_ops jump_ops = { @@ -289,7 +289,7 @@ void disasm_line__free(struct disasm_line *dl) { free(dl->line); free(dl->name); - free(dl->ops.target_name); + free(dl->ops.target.name); free(dl); } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 8a8af0d82b0..2b9e3e038a8 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -11,8 +11,11 @@ struct ins; struct ins_operands { char *raw; - char *target_name; - u64 target; + struct { + char *name; + u64 offset; + u64 addr; + } target; }; struct ins_ops { -- cgit v1.2.3-70-g09d2 From fb29fa58e36df09c807d252247d64a221fcd5bbb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 25 Apr 2012 14:16:03 -0300 Subject: perf annotate: Mark jump instructions with no offset I.e. jumps that go to code outside the current function, that is denoted in objdump -dS as: 399f877a9f: jne 399f87bcf4 <_L_lock_5154> I.e. without the + after the name of the current function, like in: 399f877aa5: jmp 399f877ab2 <_int_free+0x412> The browser will use that info to avoid drawing connectors to the start of the function, since ops.target.addr was zero. Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-xrn35g2mlawz1ydo1p73w3q6@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 9 ++++++--- tools/perf/util/annotate.h | 6 ++++++ 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'tools/perf/util/annotate.h') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index e1e7d0eb614..5eb34123f55 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -75,10 +75,13 @@ static int jump__parse(struct ins_operands *ops) { const char *s = strchr(ops->raw, '+'); - if (s++ == NULL) - return -1; + ops->target.addr = strtoll(ops->raw, NULL, 16); + + if (s++ != NULL) + ops->target.offset = strtoll(s, NULL, 16); + else + ops->target.offset = UINT64_MAX; - ops->target.offset = strtoll(s, NULL, 16); return 0; } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 2b9e3e038a8..13a21f10dab 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -2,6 +2,7 @@ #define __PERF_ANNOTATE_H #include +#include #include "types.h" #include "symbol.h" #include @@ -41,6 +42,11 @@ struct disasm_line { struct ins_operands ops; }; +static inline bool disasm_line__has_offset(const struct disasm_line *dl) +{ + return dl->ops.target.offset != UINT64_MAX; +} + void disasm_line__free(struct disasm_line *dl); struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); size_t disasm__fprintf(struct list_head *head, FILE *fp); -- cgit v1.2.3-70-g09d2