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.c | 72 ++++++++++++++++++++++------------------------ tools/perf/util/annotate.h | 11 ++++--- 2 files changed, 40 insertions(+), 43 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 1e7fd52bd29d..ef1d57def76d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -78,36 +78,35 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, return 0; } -static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize) +static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) { - struct objdump_line *self = malloc(sizeof(*self) + privsize); + struct disasm_line *dl = malloc(sizeof(*dl) + privsize); - if (self != NULL) { - self->offset = offset; - self->line = strdup(line); - if (self->line == NULL) + if (dl != NULL) { + dl->offset = offset; + dl->line = strdup(line); + if (dl->line == NULL) goto out_delete; } - return self; + return dl; out_delete: - free(self); + free(dl); return NULL; } -void objdump_line__free(struct objdump_line *self) +void disasm_line__free(struct disasm_line *dl) { - free(self->line); - free(self); + free(dl->line); + free(dl); } -static void objdump__add_line(struct list_head *head, struct objdump_line *line) +static void disasm__add(struct list_head *head, struct disasm_line *line) { list_add_tail(&line->node, head); } -struct objdump_line *objdump__get_next_ip_line(struct list_head *head, - struct objdump_line *pos) +struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos) { list_for_each_entry_continue(pos, head, node) if (pos->offset >= 0) @@ -116,15 +115,14 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head, return NULL; } -static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, - u64 start, int evidx, u64 len, int min_pcnt, - int printed, int max_lines, - struct objdump_line *queue) +static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, + int evidx, u64 len, int min_pcnt, int printed, + int max_lines, struct disasm_line *queue) { static const char *prev_line; static const char *prev_color; - if (oline->offset != -1) { + if (dl->offset != -1) { const char *path = NULL; unsigned int hits = 0; double percent = 0.0; @@ -132,11 +130,11 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, struct annotation *notes = symbol__annotation(sym); struct source_line *src_line = notes->src->lines; struct sym_hist *h = annotation__histogram(notes, evidx); - s64 offset = oline->offset; + s64 offset = dl->offset; const u64 addr = start + offset; - struct objdump_line *next; + struct disasm_line *next; - next = objdump__get_next_ip_line(¬es->src->source, oline); + next = disasm__get_next_ip_line(¬es->src->source, dl); while (offset < (s64)len && (next == NULL || offset < next->offset)) { @@ -161,9 +159,9 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, if (queue != NULL) { list_for_each_entry_from(queue, ¬es->src->source, node) { - if (queue == oline) + if (queue == dl) break; - objdump_line__print(queue, sym, start, evidx, len, + disasm_line__print(queue, sym, start, evidx, len, 0, 0, 1, NULL); } } @@ -187,17 +185,17 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, color_fprintf(stdout, color, " %7.2f", percent); printf(" : "); color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); - color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line); + color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); } else if (max_lines && printed >= max_lines) return 1; else { if (queue) return -1; - if (!*oline->line) + if (!*dl->line) printf(" :\n"); else - printf(" : %s\n", oline->line); + printf(" : %s\n", dl->line); } return 0; @@ -207,7 +205,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, FILE *file, size_t privsize) { struct annotation *notes = symbol__annotation(sym); - struct objdump_line *objdump_line; + struct disasm_line *dl; char *line = NULL, *parsed_line, *tmp, *tmp2, *c; size_t line_len; s64 line_ip, offset = -1; @@ -258,13 +256,13 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, parsed_line = tmp2 + 1; } - objdump_line = objdump_line__new(offset, parsed_line, privsize); + dl = disasm_line__new(offset, parsed_line, privsize); free(line); - if (objdump_line == NULL) + if (dl == NULL) return -1; - objdump__add_line(¬es->src->source, objdump_line); + disasm__add(¬es->src->source, dl); return 0; } @@ -503,7 +501,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, struct dso *dso = map->dso; const char *filename = dso->long_name, *d_filename; struct annotation *notes = symbol__annotation(sym); - struct objdump_line *pos, *queue = NULL; + struct disasm_line *pos, *queue = NULL; u64 start = map__rip_2objdump(map, sym->start); int printed = 2, queue_len = 0; int more = 0; @@ -528,7 +526,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, queue_len = 0; } - switch (objdump_line__print(pos, sym, start, evidx, len, + switch (disasm_line__print(pos, sym, start, evidx, len, min_pcnt, printed, max_lines, queue)) { case 0: @@ -583,13 +581,13 @@ 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) { - struct objdump_line *pos, *n; + struct disasm_line *pos, *n; list_for_each_entry_safe(pos, n, head, node) { list_del(&pos->node); - objdump_line__free(pos); + disasm_line__free(pos); } } @@ -618,7 +616,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, if (print_lines) symbol__free_source_line(sym, len); - objdump_line_list__purge(&symbol__annotation(sym)->src->source); + disasm__purge(&symbol__annotation(sym)->src->source); return 0; } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index efa5dc82bfae..8bb68bb2a04a 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-59-g8ed1b 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') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ef1d57def76d..a72585ab52e8 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 8bb68bb2a04a..dd7636d24133 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-59-g8ed1b 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') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 0bc3e652b541..bdbb54fd05ae 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 a72585ab52e8..4ee2c07924bc 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 dd7636d24133..934c6fe3a91b 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-59-g8ed1b 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') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index bdbb54fd05ae..46ef966ccc5b 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 4ee2c07924bc..a4296fdd9a68 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 934c6fe3a91b..a2105f204a42 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-59-g8ed1b 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') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 46ef966ccc5b..f7d2db3e8464 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 a4296fdd9a68..ed1f89d7044e 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 a2105f204a42..6314335007f0 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-59-g8ed1b From 1b2e2df4e395293e65dbda49e58cb4c7abeb7507 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Apr 2012 10:57:06 -0300 Subject: perf symbols: Introduce symbol__size method Fixing some off by one cases in the process. 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-fxumzufhk829z0q9anmvemea@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 10 +++++----- tools/perf/util/symbol.h | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ed1f89d7044e..d8e2f414e610 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -101,7 +101,7 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym) int symbol__alloc_hist(struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); - const size_t size = sym->end - sym->start + 1; + const size_t size = symbol__size(sym); size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); @@ -609,7 +609,7 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx) { struct annotation *notes = symbol__annotation(sym); struct sym_hist *h = annotation__histogram(notes, evidx); - u64 len = sym->end - sym->start, offset; + u64 len = symbol__size(sym), offset; for (offset = 0; offset < len; ++offset) if (h->addr[offset] != 0) @@ -636,7 +636,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, else d_filename = basename(filename); - len = sym->end - sym->start; + len = symbol__size(sym); printf(" Percent | Source code & Disassembly of %s\n", d_filename); printf("------------------------------------------------\n"); @@ -696,7 +696,7 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) { struct annotation *notes = symbol__annotation(sym); struct sym_hist *h = annotation__histogram(notes, evidx); - int len = sym->end - sym->start, offset; + int len = symbol__size(sym), offset; h->sum = 0; for (offset = 0; offset < len; ++offset) { @@ -755,7 +755,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, if (symbol__annotate(sym, map, 0) < 0) return -1; - len = sym->end - sym->start; + len = symbol__size(sym); if (print_lines) { symbol__get_source_line(sym, map, evidx, &source_line, diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index ac49ef208a5f..1f003884f1ab 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -65,6 +65,11 @@ struct symbol { void symbol__delete(struct symbol *sym); +static inline size_t symbol__size(const struct symbol *sym) +{ + return sym->end - sym->start + 1; +} + struct strlist; struct symbol_conf { -- cgit v1.2.3-59-g8ed1b From 61e04b332e9417720c331eb39c96a4ccb1aa0460 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Apr 2012 13:15:24 -0300 Subject: perf annotate browser: Align jump labels Find out at browser startup the max width and use it when rendering jump labels on the screen. 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-7dxjiwqb77wz6f5lc05e0i0x@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 17 +++++++++++++---- tools/perf/util/util.c | 10 ++++++++++ tools/perf/util/util.h | 2 ++ 3 files changed, 25 insertions(+), 4 deletions(-) (limited to 'tools/perf/util') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index a1e942bb903b..c5ab21c50a74 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -31,6 +31,7 @@ struct annotate_browser { bool hide_src_code; bool use_offset; bool searching_backwards; + u8 offset_width; char search_bf[128]; }; @@ -92,10 +93,17 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro if (!ab->use_offset) addr += ab->start; - if (bdl->jump_target || !ab->use_offset) - printed = scnprintf(bf, sizeof(bf), " %" PRIx64 ":", addr); - else - printed = scnprintf(bf, sizeof(bf), " "); + if (!ab->use_offset) { + printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ":", addr); + } else { + if (bdl->jump_target) { + printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ":", + ab->offset_width, addr); + } else { + printed = scnprintf(bf, sizeof(bf), "%*s ", + ab->offset_width, " "); + } + } if (change_color) color = ui_browser__set_color(self, HE_COLORSET_ADDR); @@ -687,6 +695,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, annotate_browser__mark_jump_targets(&browser, size); + browser.offset_width = hex_width(size); browser.b.nr_entries = browser.nr_entries; browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ 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) return buf - buf_start; } + +size_t hex_width(u64 v) +{ + size_t n = 1; + + while ((v >>= 4)) + ++n; + + return n; +} diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 0f99f394d8e0..6121e24fefc0 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -265,4 +265,6 @@ bool is_power_of_2(unsigned long n) return (n != 0 && ((n & (n - 1)) == 0)); } +size_t hex_width(u64 v); + #endif -- cgit v1.2.3-59-g8ed1b From 3f862fd076275c442dfe295eddb5650a6e0aecd4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 19 Apr 2012 17:10:12 -0300 Subject: perf annotate: Add missing jump variants Taken from binutils: [acme@sandy binutils-2.22]$ grep ^j opcodes/i386-opc.tbl | cut -d, -f1 | sort -u 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-mwshob8n12jlsu458ghvheos@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'tools/perf/util') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index d8e2f414e610..e70cbb4f3bed 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -70,11 +70,40 @@ static struct ins instructions[] = { { .name = "call", .ops = &call_ops, }, { .name = "callq", .ops = &call_ops, }, { .name = "ja", .ops = &jump_ops, }, + { .name = "jae", .ops = &jump_ops, }, + { .name = "jb", .ops = &jump_ops, }, + { .name = "jbe", .ops = &jump_ops, }, + { .name = "jc", .ops = &jump_ops, }, + { .name = "jcxz", .ops = &jump_ops, }, { .name = "je", .ops = &jump_ops, }, + { .name = "jecxz", .ops = &jump_ops, }, + { .name = "jg", .ops = &jump_ops, }, + { .name = "jge", .ops = &jump_ops, }, + { .name = "jl", .ops = &jump_ops, }, + { .name = "jle", .ops = &jump_ops, }, { .name = "jmp", .ops = &jump_ops, }, { .name = "jmpq", .ops = &jump_ops, }, + { .name = "jna", .ops = &jump_ops, }, + { .name = "jnae", .ops = &jump_ops, }, + { .name = "jnb", .ops = &jump_ops, }, + { .name = "jnbe", .ops = &jump_ops, }, + { .name = "jnc", .ops = &jump_ops, }, { .name = "jne", .ops = &jump_ops, }, + { .name = "jng", .ops = &jump_ops, }, + { .name = "jnge", .ops = &jump_ops, }, + { .name = "jnl", .ops = &jump_ops, }, + { .name = "jnle", .ops = &jump_ops, }, + { .name = "jno", .ops = &jump_ops, }, + { .name = "jnp", .ops = &jump_ops, }, + { .name = "jns", .ops = &jump_ops, }, + { .name = "jnz", .ops = &jump_ops, }, + { .name = "jo", .ops = &jump_ops, }, + { .name = "jp", .ops = &jump_ops, }, + { .name = "jpe", .ops = &jump_ops, }, + { .name = "jpo", .ops = &jump_ops, }, + { .name = "jrcxz", .ops = &jump_ops, }, { .name = "js", .ops = &jump_ops, }, + { .name = "jz", .ops = &jump_ops, }, }; static int ins__cmp(const void *name, const void *insp) -- cgit v1.2.3-59-g8ed1b 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') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index e760326efca0..9c7b6d87822e 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 e70cbb4f3bed..7f6c14b3fd7f 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 6314335007f0..a6f60d5c5138 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-59-g8ed1b 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') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 7f6c14b3fd7f..b07d7d1425f9 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 a6f60d5c5138..8a8af0d82b07 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-59-g8ed1b 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') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 4c83fe3d7dad..73e1ef0081d4 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 b07d7d1425f9..e1e7d0eb6145 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 8a8af0d82b07..2b9e3e038a84 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-59-g8ed1b 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') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index e1e7d0eb6145..5eb34123f55b 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 2b9e3e038a84..13a21f10dabb 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-59-g8ed1b