From f40a06339fe6f4809b5851a74aae2c0dc4386e1b Mon Sep 17 00:00:00 2001 From: David Miller Date: Sun, 25 Mar 2012 16:28:12 -0400 Subject: perf annotate: addr2line wants addresses in same format as objdump Therefore, in symbol__get_source_line(), use map__rip_2objdump instead of calling map->unmap_ip() unconditionally. Link: http://lkml.kernel.org/r/20120325.162812.59519424882536855.davem@davemloft.net Signed-off-by: David S. Miller Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index e5a462f1d07..31ba2a20c0f 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -408,7 +408,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, if (!notes->src->lines) return -1; - start = map->unmap_ip(map, sym->start); + start = map__rip_2objdump(map, sym->start); for (i = 0; i < len; i++) { char *path = NULL; -- cgit v1.2.3-70-g09d2 From 64c17be4ffb8d6971051aec77ca1de4cfadb166d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 28 Mar 2012 12:49:35 -0300 Subject: perf annotate: Fix off by one symbol hist size allocation and hit accounting We were not noticing it because symbol__inc_addr_samples was erroneously dropping samples that hit the last byte in a function. Working on a fix for a problem reported by David Miller, Stephane Eranian and Sorin Dumitru, where addresses < sym->start were causing problems, I noticed this other problem. Cc: David Ahern Cc: David Miller Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Sorin Dumitru Cc: Stephane Eranian Link: http://lkml.kernel.org/n/tip-pqjaq4cr1xs2xen73pjhbav4@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 31ba2a20c0f..199f69ec656 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -28,8 +28,8 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym) int symbol__alloc_hist(struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); - size_t sizeof_sym_hist = (sizeof(struct sym_hist) + - (sym->end - sym->start) * sizeof(u64)); + const size_t size = sym->end - sym->start + 1; + 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); if (notes->src == NULL) @@ -64,7 +64,7 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); - if (addr >= sym->end) + if (addr > sym->end) return 0; offset = addr - sym->start; -- cgit v1.2.3-70-g09d2 From 8b84a568117fde9b77575f2060274eddab424c32 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 5 Apr 2012 16:15:59 -0300 Subject: perf annotate: Fix hist decay We were only decaying the entries for the offsets that were associated with an objdump line. That way, when we accrued the whole instruction addr range, more than 100% was appearing in some cases in the live annotation TUI. Fix it by not traversing the source code line at all, just iterate thru the complete addr range decaying each one. Reported-by: Mike Galbraith 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-hcae5oxa22syjrnalsxz7s6n@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 199f69ec656..70f5a4dc17e 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -561,16 +561,12 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) { struct annotation *notes = symbol__annotation(sym); struct sym_hist *h = annotation__histogram(notes, evidx); - struct objdump_line *pos; - int len = sym->end - sym->start; + int len = sym->end - sym->start, offset; h->sum = 0; - - list_for_each_entry(pos, ¬es->src->source, node) { - if (pos->offset != -1 && pos->offset < len) { - h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8; - h->sum += h->addr[pos->offset]; - } + for (offset = 0; offset < len; ++offset) { + h->addr[offset] = h->addr[offset] * 7 / 8; + h->sum += h->addr[offset]; } } -- cgit v1.2.3-70-g09d2 From 31d68e7b66f168e623902e194af1e52b8cf75d71 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 27 Mar 2012 12:55:57 -0300 Subject: perf annotate: Validate addr in symbol__inc_addr_samples This routine was checking only if the provided address was after sym->end, not if it was before sym->start. Fix that by checking for both and return in both cases -ERANGE, so that tools can communicate this to the user properly, or if they chose so, to abort. This problem was reported previously but the fixes involved either doing what was being done for the > end case, i.e. silently drop the sample, returning 0, or aborting at this function, which is in a lib (or better, is slated to be at some point) and shouldn't abort. The 'report' tool already checks this value and uses pr_debug to warn the user. This patch makes the 'top' tool check it too and warn once per map where such range problem takes place. Reported-by: David Miller Reported-by: Sorin Dumitru Reported-by: Stephane Eranian Cc: David Ahern Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-lw8gs7p9i9nhldilo82tzpne@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 35 ++++++++++++++++++++++++++++++++++- tools/perf/util/annotate.c | 4 ++-- tools/perf/util/map.c | 1 + tools/perf/util/map.h | 1 + 4 files changed, 38 insertions(+), 3 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index fab0a1c7e87..8ef59f8262b 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -42,6 +42,7 @@ #include "util/debug.h" #include +#include #include #include @@ -59,6 +60,7 @@ #include #include #include +#include #include #include @@ -162,12 +164,40 @@ static void __zero_source_counters(struct hist_entry *he) symbol__annotate_zero_histograms(sym); } +static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) +{ + struct utsname uts; + int err = uname(&uts); + + ui__warning("Out of bounds address found:\n\n" + "Addr: %" PRIx64 "\n" + "DSO: %s %c\n" + "Map: %" PRIx64 "-%" PRIx64 "\n" + "Symbol: %" PRIx64 "-%" PRIx64 " %c %s\n" + "Arch: %s\n" + "Kernel: %s\n" + "Tools: %s\n\n" + "Not all samples will be on the annotation output.\n\n" + "Please report to linux-kernel@vger.kernel.org\n", + ip, map->dso->long_name, dso__symtab_origin(map->dso), + map->start, map->end, sym->start, sym->end, + sym->binding == STB_GLOBAL ? 'g' : + sym->binding == STB_LOCAL ? 'l' : 'w', sym->name, + err ? "[unknown]" : uts.machine, + err ? "[unknown]" : uts.release, perf_version_string); + if (use_browser <= 0) + sleep(5); + + map->erange_warned = true; +} + static void perf_top__record_precise_ip(struct perf_top *top, struct hist_entry *he, int counter, u64 ip) { struct annotation *notes; struct symbol *sym; + int err; if (he == NULL || he->ms.sym == NULL || ((top->sym_filter_entry == NULL || @@ -189,9 +219,12 @@ static void perf_top__record_precise_ip(struct perf_top *top, } ip = he->ms.map->map_ip(he->ms.map, ip); - symbol__inc_addr_samples(sym, he->ms.map, counter, ip); + err = symbol__inc_addr_samples(sym, he->ms.map, counter, ip); pthread_mutex_unlock(¬es->lock); + + if (err == -ERANGE && !he->ms.map->erange_warned) + ui__warn_map_erange(he->ms.map, sym, ip); } static void perf_top__show_details(struct perf_top *top) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 70f5a4dc17e..08c6d138a65 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -64,8 +64,8 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); - if (addr > sym->end) - return 0; + if (addr < sym->start || addr > sym->end) + return -ERANGE; offset = addr - sym->start; h = annotation__histogram(notes, evidx); diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index dea6d1c1a95..35ae56864e4 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -38,6 +38,7 @@ void map__init(struct map *self, enum map_type type, RB_CLEAR_NODE(&self->rb_node); self->groups = NULL; self->referenced = false; + self->erange_warned = false; } struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index b100c20b7f9..81371bad4ef 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -33,6 +33,7 @@ struct map { u64 end; u8 /* enum map_type */ type; bool referenced; + bool erange_warned; u32 priv; u64 pgoff; -- cgit v1.2.3-70-g09d2 From 058b4cc9af574c072988a38a7a5ee93df881e5aa Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 2 Apr 2012 12:59:01 -0300 Subject: perf annotate: Allow printing objdump line addr in different color And by default use "magenta" for it. Both the --stdio and --tui routines follow the same semantics. 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-ede5zkaf7oorwvbqjezb4yg4@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perfconfig.example | 1 + tools/perf/util/annotate.c | 35 ++++++++++++++++++++--------- tools/perf/util/ui/browser.c | 6 +++++ tools/perf/util/ui/browser.h | 1 + tools/perf/util/ui/browsers/annotate.c | 26 ++++++++++++++++----- 5 files changed, 53 insertions(+), 16 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example index d1448668f4d..42c6fd2ae85 100644 --- a/tools/perf/Documentation/perfconfig.example +++ b/tools/perf/Documentation/perfconfig.example @@ -6,6 +6,7 @@ normal = black, lightgray selected = lightgray, magenta code = blue, lightgray + addr = magenta, lightgray [tui] diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 08c6d138a65..9fc4126e54d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -84,10 +84,15 @@ static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t pri if (self != NULL) { self->offset = offset; - self->line = line; + self->line = strdup(line); + if (self->line == NULL) + goto out_delete; } return self; +out_delete: + free(self); + return NULL; } void objdump_line__free(struct objdump_line *self) @@ -112,7 +117,7 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head, } static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, - int evidx, u64 len, int min_pcnt, + u64 start, int evidx, u64 len, int min_pcnt, int printed, int max_lines, struct objdump_line *queue) { @@ -128,6 +133,7 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, struct source_line *src_line = notes->src->lines; struct sym_hist *h = annotation__histogram(notes, evidx); s64 offset = oline->offset; + const u64 addr = start + offset; struct objdump_line *next; next = objdump__get_next_ip_line(¬es->src->source, oline); @@ -157,7 +163,7 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, list_for_each_entry_from(queue, ¬es->src->source, node) { if (queue == oline) break; - objdump_line__print(queue, sym, evidx, len, + objdump_line__print(queue, sym, start, evidx, len, 0, 0, 1, NULL); } } @@ -180,6 +186,7 @@ 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); } else if (max_lines && printed >= max_lines) return 1; @@ -201,7 +208,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, { struct annotation *notes = symbol__annotation(sym); struct objdump_line *objdump_line; - char *line = NULL, *tmp, *tmp2, *c; + char *line = NULL, *parsed_line, *tmp, *tmp2, *c; size_t line_len; s64 line_ip, offset = -1; @@ -246,13 +253,17 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, offset = line_ip - start; if (offset < 0 || (u64)line_ip > end) offset = -1; - } + else + parsed_line = tmp2 + 1; + } else + parsed_line = line; - objdump_line = objdump_line__new(offset, line, privsize); - if (objdump_line == NULL) { - free(line); + objdump_line = objdump_line__new(offset, parsed_line, privsize); + free(line); + + if (objdump_line == NULL) return -1; - } + objdump__add_line(¬es->src->source, objdump_line); return 0; @@ -493,6 +504,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, const char *filename = dso->long_name, *d_filename; struct annotation *notes = symbol__annotation(sym); struct objdump_line *pos, *queue = NULL; + u64 start = map__rip_2objdump(map, sym->start); int printed = 2, queue_len = 0; int more = 0; u64 len; @@ -516,8 +528,9 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, queue_len = 0; } - switch (objdump_line__print(pos, sym, evidx, len, min_pcnt, - printed, max_lines, queue)) { + switch (objdump_line__print(pos, sym, start, evidx, len, + min_pcnt, printed, max_lines, + queue)) { case 0: ++printed; if (context) { diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c index 076a5ffc8f5..a1b140cf75a 100644 --- a/tools/perf/util/ui/browser.c +++ b/tools/perf/util/ui/browser.c @@ -505,6 +505,12 @@ static struct ui_browser__colorset { .fg = "blue", .bg = "default", }, + { + .colorset = HE_COLORSET_ADDR, + .name = "addr", + .fg = "magenta", + .bg = "default", + }, { .name = NULL, } diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h index 65b25921529..2550277db9f 100644 --- a/tools/perf/util/ui/browser.h +++ b/tools/perf/util/ui/browser.h @@ -10,6 +10,7 @@ #define HE_COLORSET_NORMAL 52 #define HE_COLORSET_SELECTED 53 #define HE_COLORSET_CODE 54 +#define HE_COLORSET_ADDR 55 struct ui_browser { u64 index, top_idx; diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 57a4c6ef3fd..7ac7dd04d5c 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -16,6 +16,7 @@ struct annotate_browser { struct rb_root entries; struct rb_node *curr_hot; struct objdump_line *selection; + u64 start; int nr_asm_entries; int nr_entries; bool hide_src_code; @@ -51,6 +52,9 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro struct annotate_browser *ab = container_of(self, struct annotate_browser, b); struct objdump_line *ol = list_entry(entry, struct objdump_line, node); bool current_entry = ui_browser__is_current_entry(self, row); + bool change_color = (!ab->hide_src_code && + (!current_entry || (self->use_navkeypressed && + !self->navkeypressed))); int width = self->width; if (ol->offset != -1) { @@ -69,15 +73,26 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro if (!self->navkeypressed) width += 1; - if (!ab->hide_src_code && ol->offset != -1) - if (!current_entry || (self->use_navkeypressed && - !self->navkeypressed)) - ui_browser__set_color(self, HE_COLORSET_CODE); + if (ol->offset != -1 && change_color) + ui_browser__set_color(self, HE_COLORSET_CODE); if (!*ol->line) slsmg_write_nstring(" ", width - 18); - else + else if (ol->offset == -1) slsmg_write_nstring(ol->line, width - 18); + else { + char bf[64]; + u64 addr = ab->start + ol->offset; + int printed = scnprintf(bf, sizeof(bf), " %" PRIx64 ":", addr); + int color = -1; + + if (change_color) + color = ui_browser__set_color(self, HE_COLORSET_ADDR); + slsmg_write_nstring(bf, printed); + if (change_color) + ui_browser__set_color(self, color); + slsmg_write_nstring(ol->line, width - 18 - printed); + } if (current_entry) ab->selection = ol; @@ -406,6 +421,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, ui_helpline__push("Press <- or ESC to exit"); notes = symbol__annotation(sym); + browser.start = map__rip_2objdump(map, sym->start); list_for_each_entry(pos, ¬es->src->source, node) { struct objdump_line_rb_node *rbpos; -- cgit v1.2.3-70-g09d2 From a31b7cc083b1d3d15bd475729fc4471685ebc5f6 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 11 Apr 2012 17:04:59 -0300 Subject: perf annotate: Fix a build error CC util/annotate.o util/annotate.c: In function symbol__annotate: util/annotate.c:87:16: error: parsed_line may be used uninitialized in this function [-Werror=maybe-uninitialized] util/annotate.c:211:22: note: parsed_line was declared here cc1: all warnings being treated as errors make: *** [util/annotate.o] Error 1 make: *** Waiting for unfinished jobs.... Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Ashay Rane Cc: David Ahern Cc: Frederic Weisbecker Cc: Masami Hiramatsu Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/87ty0tlv4i.fsf@dasan.aot.lge.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 9fc4126e54d..1e7fd52bd29 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -226,6 +226,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, *c = 0; line_ip = -1; + parsed_line = line; /* * Strip leading spaces: @@ -255,8 +256,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, offset = -1; else parsed_line = tmp2 + 1; - } else - parsed_line = line; + } objdump_line = objdump_line__new(offset, parsed_line, privsize); free(line); -- cgit v1.2.3-70-g09d2