aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2012-04-27 03:00:50 -0400
committerIngo Molnar <mingo@kernel.org>2012-04-27 03:00:50 -0400
commit1fa2e84db3f95adab8d9c2aa245e9a0ebf32248a (patch)
treef7dfb02a99d680c9c577d93dd704b822a66a39a6 /tools
parent392d65a9adbe2f09707d2de27110dafb9c8dc08b (diff)
parent38b31bd0cefbb0e69a182d9a94b09a7e648549dc (diff)
Merge tag 'perf-annotate-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Annotation improvements: Now the default annotate browser uses a much more compact format, implementing suggestions made made by several people, notably Linus. Here is part of the new __list_del_entry() annotation: __list_del_entry 8.47 │ push %rbp 8.47 │ mov (%rdi),%rdx 20.34 │ mov $0xdead000000100100,%rcx 3.39 │ mov 0x8(%rdi),%rax 0.00 │ mov %rsp,%rbp 1.69 │ cmp %rcx,%rdx 0.00 │ je 43 1.69 │ mov $0xdead000000200200,%rcx 3.39 │ cmp %rcx,%rax 0.00 │ je a3 5.08 │ mov (%rax),%r8 18.64 │ cmp %r8,%rdi 0.00 │ jne 84 1.69 │ mov 0x8(%rdx),%r8 25.42 │ cmp %r8,%rdi 0.00 │ jne 65 1.69 │ mov %rax,0x8(%rdx) 0.00 │ mov %rdx,(%rax) 0.00 │ leaveq 0.00 │ retq 0.00 │ 43: mov %rdx,%r8 0.00 │ mov %rdi,%rcx 0.00 │ mov $0xffffffff817cd6a8,%rdx 0.00 │ mov $0x31,%esi 0.00 │ mov $0xffffffff817cd6e0,%rdi 0.00 │ xor %eax,%eax 0.00 │ callq ffffffff8104eab0 <warn_slowpath_fmt> 0.00 │ leaveq 0.00 │ retq 0.00 │ 65: mov %rdi,%rcx 0.00 │ mov $0xffffffff817cd780,%rdx 0.00 │ mov $0x3a,%esi 0.00 │ mov $0xffffffff817cd6e0,%rdi 0.00 │ xor %eax,%eax 0.00 │ callq ffffffff8104eab0 <warn_slowpath_fmt> 0.00 │ leaveq 0.00 │ retq The infrastructure is there to provide formatters for any instruction, like the one I'll do for call functions to elide the address. Further fixes on top of the first iteration: - Sometimes a jump points to an offset with no instructions, make the mark jump targets function handle that, for now just ignoring such jump targets, more investigation is needed to figure out how to cope with that. - Handle jump targets that are outside the function, for now just don't try to draw the connector arrow, right thing seems to be to mark this jump with a -> (right arrow) and handle it like a callq. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/ui/browser.c46
-rw-r--r--tools/perf/ui/browser.h3
-rw-r--r--tools/perf/ui/browsers/annotate.c417
-rw-r--r--tools/perf/util/annotate.c305
-rw-r--r--tools/perf/util/annotate.h52
-rw-r--r--tools/perf/util/symbol.h5
-rw-r--r--tools/perf/util/util.c10
-rw-r--r--tools/perf/util/util.h2
8 files changed, 645 insertions, 195 deletions
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index a1b140cf75ac..32ac1165100d 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -593,6 +593,52 @@ unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
593 return row; 593 return row;
594} 594}
595 595
596void ui_browser__write_graph(struct ui_browser *browser __used, int graph)
597{
598 SLsmg_set_char_set(1);
599 SLsmg_write_char(graph);
600 SLsmg_set_char_set(0);
601}
602
603void __ui_browser__line_arrow_up(struct ui_browser *browser, unsigned int column,
604 u64 start, u64 end, int start_width)
605{
606 unsigned int row, end_row;
607
608 SLsmg_set_char_set(1);
609
610 if (start < browser->top_idx + browser->height) {
611 row = start - browser->top_idx;
612 ui_browser__gotorc(browser, row, column);
613 SLsmg_write_char(SLSMG_LLCORN_CHAR);
614 ui_browser__gotorc(browser, row, column + 1);
615 SLsmg_draw_hline(start_width);
616
617 if (row-- == 0)
618 goto out;
619 } else
620 row = browser->height - 1;
621
622 if (end > browser->top_idx)
623 end_row = end - browser->top_idx;
624 else
625 end_row = 0;
626
627 ui_browser__gotorc(browser, end_row, column);
628 SLsmg_draw_vline(row - end_row + 1);
629
630 ui_browser__gotorc(browser, end_row, column);
631 if (end >= browser->top_idx) {
632 SLsmg_write_char(SLSMG_ULCORN_CHAR);
633 ui_browser__gotorc(browser, end_row, column + 1);
634 SLsmg_write_char(SLSMG_HLINE_CHAR);
635 ui_browser__gotorc(browser, end_row, column + 2);
636 SLsmg_write_char(SLSMG_RARROW_CHAR);
637 }
638out:
639 SLsmg_set_char_set(0);
640}
641
596void ui_browser__init(void) 642void ui_browser__init(void)
597{ 643{
598 int i = 0; 644 int i = 0;
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
index 2550277db9f9..2f226cb79f6a 100644
--- a/tools/perf/ui/browser.h
+++ b/tools/perf/ui/browser.h
@@ -37,6 +37,9 @@ void ui_browser__refresh_dimensions(struct ui_browser *self);
37void ui_browser__reset_index(struct ui_browser *self); 37void ui_browser__reset_index(struct ui_browser *self);
38 38
39void ui_browser__gotorc(struct ui_browser *self, int y, int x); 39void ui_browser__gotorc(struct ui_browser *self, int y, int x);
40void ui_browser__write_graph(struct ui_browser *browser, int graph);
41void __ui_browser__line_arrow_up(struct ui_browser *browser, unsigned int column,
42 u64 start, u64 end, int start_width);
40void __ui_browser__show_title(struct ui_browser *browser, const char *title); 43void __ui_browser__show_title(struct ui_browser *browser, const char *title);
41void ui_browser__show_title(struct ui_browser *browser, const char *title); 44void ui_browser__show_title(struct ui_browser *browser, const char *title);
42int ui_browser__show(struct ui_browser *self, const char *title, 45int ui_browser__show(struct ui_browser *self, const char *title,
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 4db5186472b5..077380baa1c0 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -11,40 +11,42 @@
11#include <pthread.h> 11#include <pthread.h>
12#include <newt.h> 12#include <newt.h>
13 13
14struct browser_disasm_line {
15 struct rb_node rb_node;
16 double percent;
17 u32 idx;
18 int idx_asm;
19 bool jump_target;
20};
21
14struct annotate_browser { 22struct annotate_browser {
15 struct ui_browser b; 23 struct ui_browser b;
16 struct rb_root entries; 24 struct rb_root entries;
17 struct rb_node *curr_hot; 25 struct rb_node *curr_hot;
18 struct objdump_line *selection; 26 struct disasm_line *selection;
27 struct disasm_line **offsets;
19 u64 start; 28 u64 start;
20 int nr_asm_entries; 29 int nr_asm_entries;
21 int nr_entries; 30 int nr_entries;
22 bool hide_src_code; 31 bool hide_src_code;
23 bool use_offset; 32 bool use_offset;
24 bool searching_backwards; 33 bool searching_backwards;
34 u8 offset_width;
25 char search_bf[128]; 35 char search_bf[128];
26}; 36};
27 37
28struct objdump_line_rb_node { 38static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
29 struct rb_node rb_node;
30 double percent;
31 u32 idx;
32 int idx_asm;
33};
34
35static inline
36struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
37{ 39{
38 return (struct objdump_line_rb_node *)(self + 1); 40 return (struct browser_disasm_line *)(dl + 1);
39} 41}
40 42
41static bool objdump_line__filter(struct ui_browser *browser, void *entry) 43static bool disasm_line__filter(struct ui_browser *browser, void *entry)
42{ 44{
43 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); 45 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
44 46
45 if (ab->hide_src_code) { 47 if (ab->hide_src_code) {
46 struct objdump_line *ol = list_entry(entry, struct objdump_line, node); 48 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
47 return ol->offset == -1; 49 return dl->offset == -1;
48 } 50 }
49 51
50 return false; 52 return false;
@@ -53,72 +55,160 @@ static bool objdump_line__filter(struct ui_browser *browser, void *entry)
53static void annotate_browser__write(struct ui_browser *self, void *entry, int row) 55static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
54{ 56{
55 struct annotate_browser *ab = container_of(self, struct annotate_browser, b); 57 struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
56 struct objdump_line *ol = list_entry(entry, struct objdump_line, node); 58 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
59 struct browser_disasm_line *bdl = disasm_line__browser(dl);
57 bool current_entry = ui_browser__is_current_entry(self, row); 60 bool current_entry = ui_browser__is_current_entry(self, row);
58 bool change_color = (!ab->hide_src_code && 61 bool change_color = (!ab->hide_src_code &&
59 (!current_entry || (self->use_navkeypressed && 62 (!current_entry || (self->use_navkeypressed &&
60 !self->navkeypressed))); 63 !self->navkeypressed)));
61 int width = self->width; 64 int width = self->width;
62 65
63 if (ol->offset != -1) { 66 if (dl->offset != -1) {
64 struct objdump_line_rb_node *olrb = objdump_line__rb(ol); 67 ui_browser__set_percent_color(self, bdl->percent, current_entry);
65 ui_browser__set_percent_color(self, olrb->percent, current_entry); 68 slsmg_printf(" %7.2f ", bdl->percent);
66 slsmg_printf(" %7.2f ", olrb->percent);
67 } else { 69 } else {
68 ui_browser__set_percent_color(self, 0, current_entry); 70 ui_browser__set_percent_color(self, 0, current_entry);
69 slsmg_write_nstring(" ", 9); 71 slsmg_write_nstring(" ", 9);
70 } 72 }
71 73
72 SLsmg_write_char(':'); 74 ui_browser__write_graph(self, SLSMG_VLINE_CHAR);
73 slsmg_write_nstring(" ", 8); 75 SLsmg_write_char(' ');
74 76
75 /* The scroll bar isn't being used */ 77 /* The scroll bar isn't being used */
76 if (!self->navkeypressed) 78 if (!self->navkeypressed)
77 width += 1; 79 width += 1;
78 80
79 if (ol->offset != -1 && change_color) 81 if (dl->offset != -1 && change_color)
80 ui_browser__set_color(self, HE_COLORSET_CODE); 82 ui_browser__set_color(self, HE_COLORSET_CODE);
81 83
82 if (!*ol->line) 84 if (!*dl->line)
83 slsmg_write_nstring(" ", width - 18); 85 slsmg_write_nstring(" ", width - 10);
84 else if (ol->offset == -1) 86 else if (dl->offset == -1)
85 slsmg_write_nstring(ol->line, width - 18); 87 slsmg_write_nstring(dl->line, width - 10);
86 else { 88 else {
87 char bf[64]; 89 char bf[256];
88 u64 addr = ol->offset; 90 u64 addr = dl->offset;
89 int printed, color = -1; 91 int printed, color = -1;
90 92
91 if (!ab->use_offset) 93 if (!ab->use_offset)
92 addr += ab->start; 94 addr += ab->start;
93 95
94 printed = scnprintf(bf, sizeof(bf), " %" PRIx64 ":", addr); 96 if (!ab->use_offset) {
97 printed = scnprintf(bf, sizeof(bf), " %" PRIx64 ":", addr);
98 } else {
99 if (bdl->jump_target) {
100 printed = scnprintf(bf, sizeof(bf), " %*" PRIx64 ":",
101 ab->offset_width, addr);
102 } else {
103 printed = scnprintf(bf, sizeof(bf), " %*s ",
104 ab->offset_width, " ");
105 }
106 }
107
95 if (change_color) 108 if (change_color)
96 color = ui_browser__set_color(self, HE_COLORSET_ADDR); 109 color = ui_browser__set_color(self, HE_COLORSET_ADDR);
97 slsmg_write_nstring(bf, printed); 110 slsmg_write_nstring(bf, printed);
98 if (change_color) 111 if (change_color)
99 ui_browser__set_color(self, color); 112 ui_browser__set_color(self, color);
100 slsmg_write_nstring(ol->line, width - 18 - printed); 113 if (dl->ins && dl->ins->ops->scnprintf) {
114 if (ins__is_jump(dl->ins)) {
115 bool fwd = dl->ops.target.offset > (u64)dl->offset;
116
117 ui_browser__write_graph(self, fwd ? SLSMG_DARROW_CHAR :
118 SLSMG_UARROW_CHAR);
119 SLsmg_write_char(' ');
120 } else {
121 slsmg_write_nstring(" ", 2);
122 }
123
124 dl->ins->ops->scnprintf(dl->ins, bf, sizeof(bf), &dl->ops,
125 !ab->use_offset);
126 } else {
127 if (strcmp(dl->name, "retq")) {
128 slsmg_write_nstring(" ", 2);
129 } else {
130 ui_browser__write_graph(self, SLSMG_LARROW_CHAR);
131 SLsmg_write_char(' ');
132 }
133
134 scnprintf(bf, sizeof(bf), "%-6.6s %s", dl->name, dl->ops.raw);
135 }
136
137 slsmg_write_nstring(bf, width - 12 - printed);
101 } 138 }
102 139
103 if (current_entry) 140 if (current_entry)
104 ab->selection = ol; 141 ab->selection = dl;
142}
143
144static void annotate_browser__draw_current_loop(struct ui_browser *browser)
145{
146 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
147 struct map_symbol *ms = browser->priv;
148 struct symbol *sym = ms->sym;
149 struct annotation *notes = symbol__annotation(sym);
150 struct disasm_line *cursor = ab->selection, *pos = cursor, *target;
151 struct browser_disasm_line *bcursor = disasm_line__browser(cursor),
152 *btarget, *bpos;
153 unsigned int from, to, start_width = 2;
154
155 list_for_each_entry_from(pos, &notes->src->source, node) {
156 if (!pos->ins || !ins__is_jump(pos->ins) ||
157 !disasm_line__has_offset(pos))
158 continue;
159
160 target = ab->offsets[pos->ops.target.offset];
161 if (!target)
162 continue;
163
164 btarget = disasm_line__browser(target);
165 if (btarget->idx <= bcursor->idx)
166 goto found;
167 }
168
169 return;
170
171found:
172 bpos = disasm_line__browser(pos);
173 if (ab->hide_src_code) {
174 from = bpos->idx_asm;
175 to = btarget->idx_asm;
176 } else {
177 from = (u64)bpos->idx;
178 to = (u64)btarget->idx;
179 }
180
181 ui_browser__set_color(browser, HE_COLORSET_CODE);
182
183 if (!bpos->jump_target)
184 start_width += ab->offset_width + 1;
185
186 __ui_browser__line_arrow_up(browser, 10, from, to, start_width);
187}
188
189static unsigned int annotate_browser__refresh(struct ui_browser *browser)
190{
191 int ret = ui_browser__list_head_refresh(browser);
192
193 annotate_browser__draw_current_loop(browser);
194
195 return ret;
105} 196}
106 197
107static double objdump_line__calc_percent(struct objdump_line *self, 198static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx)
108 struct symbol *sym, int evidx)
109{ 199{
110 double percent = 0.0; 200 double percent = 0.0;
111 201
112 if (self->offset != -1) { 202 if (dl->offset != -1) {
113 int len = sym->end - sym->start; 203 int len = sym->end - sym->start;
114 unsigned int hits = 0; 204 unsigned int hits = 0;
115 struct annotation *notes = symbol__annotation(sym); 205 struct annotation *notes = symbol__annotation(sym);
116 struct source_line *src_line = notes->src->lines; 206 struct source_line *src_line = notes->src->lines;
117 struct sym_hist *h = annotation__histogram(notes, evidx); 207 struct sym_hist *h = annotation__histogram(notes, evidx);
118 s64 offset = self->offset; 208 s64 offset = dl->offset;
119 struct objdump_line *next; 209 struct disasm_line *next;
120 210
121 next = objdump__get_next_ip_line(&notes->src->source, self); 211 next = disasm__get_next_ip_line(&notes->src->source, dl);
122 while (offset < (s64)len && 212 while (offset < (s64)len &&
123 (next == NULL || offset < next->offset)) { 213 (next == NULL || offset < next->offset)) {
124 if (src_line) { 214 if (src_line) {
@@ -139,27 +229,26 @@ static double objdump_line__calc_percent(struct objdump_line *self,
139 return percent; 229 return percent;
140} 230}
141 231
142static void objdump__insert_line(struct rb_root *self, 232static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl)
143 struct objdump_line_rb_node *line)
144{ 233{
145 struct rb_node **p = &self->rb_node; 234 struct rb_node **p = &root->rb_node;
146 struct rb_node *parent = NULL; 235 struct rb_node *parent = NULL;
147 struct objdump_line_rb_node *l; 236 struct browser_disasm_line *l;
148 237
149 while (*p != NULL) { 238 while (*p != NULL) {
150 parent = *p; 239 parent = *p;
151 l = rb_entry(parent, struct objdump_line_rb_node, rb_node); 240 l = rb_entry(parent, struct browser_disasm_line, rb_node);
152 if (line->percent < l->percent) 241 if (bdl->percent < l->percent)
153 p = &(*p)->rb_left; 242 p = &(*p)->rb_left;
154 else 243 else
155 p = &(*p)->rb_right; 244 p = &(*p)->rb_right;
156 } 245 }
157 rb_link_node(&line->rb_node, parent, p); 246 rb_link_node(&bdl->rb_node, parent, p);
158 rb_insert_color(&line->rb_node, self); 247 rb_insert_color(&bdl->rb_node, root);
159} 248}
160 249
161static void annotate_browser__set_top(struct annotate_browser *self, 250static void annotate_browser__set_top(struct annotate_browser *self,
162 struct objdump_line *pos, u32 idx) 251 struct disasm_line *pos, u32 idx)
163{ 252{
164 unsigned back; 253 unsigned back;
165 254
@@ -168,9 +257,9 @@ static void annotate_browser__set_top(struct annotate_browser *self,
168 self->b.top_idx = self->b.index = idx; 257 self->b.top_idx = self->b.index = idx;
169 258
170 while (self->b.top_idx != 0 && back != 0) { 259 while (self->b.top_idx != 0 && back != 0) {
171 pos = list_entry(pos->node.prev, struct objdump_line, node); 260 pos = list_entry(pos->node.prev, struct disasm_line, node);
172 261
173 if (objdump_line__filter(&self->b, &pos->node)) 262 if (disasm_line__filter(&self->b, &pos->node))
174 continue; 263 continue;
175 264
176 --self->b.top_idx; 265 --self->b.top_idx;
@@ -184,12 +273,12 @@ static void annotate_browser__set_top(struct annotate_browser *self,
184static void annotate_browser__set_rb_top(struct annotate_browser *browser, 273static void annotate_browser__set_rb_top(struct annotate_browser *browser,
185 struct rb_node *nd) 274 struct rb_node *nd)
186{ 275{
187 struct objdump_line_rb_node *rbpos; 276 struct browser_disasm_line *bpos;
188 struct objdump_line *pos; 277 struct disasm_line *pos;
189 278
190 rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node); 279 bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
191 pos = ((struct objdump_line *)rbpos) - 1; 280 pos = ((struct disasm_line *)bpos) - 1;
192 annotate_browser__set_top(browser, pos, rbpos->idx); 281 annotate_browser__set_top(browser, pos, bpos->idx);
193 browser->curr_hot = nd; 282 browser->curr_hot = nd;
194} 283}
195 284
@@ -199,20 +288,20 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
199 struct map_symbol *ms = browser->b.priv; 288 struct map_symbol *ms = browser->b.priv;
200 struct symbol *sym = ms->sym; 289 struct symbol *sym = ms->sym;
201 struct annotation *notes = symbol__annotation(sym); 290 struct annotation *notes = symbol__annotation(sym);
202 struct objdump_line *pos; 291 struct disasm_line *pos;
203 292
204 browser->entries = RB_ROOT; 293 browser->entries = RB_ROOT;
205 294
206 pthread_mutex_lock(&notes->lock); 295 pthread_mutex_lock(&notes->lock);
207 296
208 list_for_each_entry(pos, &notes->src->source, node) { 297 list_for_each_entry(pos, &notes->src->source, node) {
209 struct objdump_line_rb_node *rbpos = objdump_line__rb(pos); 298 struct browser_disasm_line *bpos = disasm_line__browser(pos);
210 rbpos->percent = objdump_line__calc_percent(pos, sym, evidx); 299 bpos->percent = disasm_line__calc_percent(pos, sym, evidx);
211 if (rbpos->percent < 0.01) { 300 if (bpos->percent < 0.01) {
212 RB_CLEAR_NODE(&rbpos->rb_node); 301 RB_CLEAR_NODE(&bpos->rb_node);
213 continue; 302 continue;
214 } 303 }
215 objdump__insert_line(&browser->entries, rbpos); 304 disasm_rb_tree__insert(&browser->entries, bpos);
216 } 305 }
217 pthread_mutex_unlock(&notes->lock); 306 pthread_mutex_unlock(&notes->lock);
218 307
@@ -221,38 +310,38 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser,
221 310
222static bool annotate_browser__toggle_source(struct annotate_browser *browser) 311static bool annotate_browser__toggle_source(struct annotate_browser *browser)
223{ 312{
224 struct objdump_line *ol; 313 struct disasm_line *dl;
225 struct objdump_line_rb_node *olrb; 314 struct browser_disasm_line *bdl;
226 off_t offset = browser->b.index - browser->b.top_idx; 315 off_t offset = browser->b.index - browser->b.top_idx;
227 316
228 browser->b.seek(&browser->b, offset, SEEK_CUR); 317 browser->b.seek(&browser->b, offset, SEEK_CUR);
229 ol = list_entry(browser->b.top, struct objdump_line, node); 318 dl = list_entry(browser->b.top, struct disasm_line, node);
230 olrb = objdump_line__rb(ol); 319 bdl = disasm_line__browser(dl);
231 320
232 if (browser->hide_src_code) { 321 if (browser->hide_src_code) {
233 if (olrb->idx_asm < offset) 322 if (bdl->idx_asm < offset)
234 offset = olrb->idx; 323 offset = bdl->idx;
235 324
236 browser->b.nr_entries = browser->nr_entries; 325 browser->b.nr_entries = browser->nr_entries;
237 browser->hide_src_code = false; 326 browser->hide_src_code = false;
238 browser->b.seek(&browser->b, -offset, SEEK_CUR); 327 browser->b.seek(&browser->b, -offset, SEEK_CUR);
239 browser->b.top_idx = olrb->idx - offset; 328 browser->b.top_idx = bdl->idx - offset;
240 browser->b.index = olrb->idx; 329 browser->b.index = bdl->idx;
241 } else { 330 } else {
242 if (olrb->idx_asm < 0) { 331 if (bdl->idx_asm < 0) {
243 ui_helpline__puts("Only available for assembly lines."); 332 ui_helpline__puts("Only available for assembly lines.");
244 browser->b.seek(&browser->b, -offset, SEEK_CUR); 333 browser->b.seek(&browser->b, -offset, SEEK_CUR);
245 return false; 334 return false;
246 } 335 }
247 336
248 if (olrb->idx_asm < offset) 337 if (bdl->idx_asm < offset)
249 offset = olrb->idx_asm; 338 offset = bdl->idx_asm;
250 339
251 browser->b.nr_entries = browser->nr_asm_entries; 340 browser->b.nr_entries = browser->nr_asm_entries;
252 browser->hide_src_code = true; 341 browser->hide_src_code = true;
253 browser->b.seek(&browser->b, -offset, SEEK_CUR); 342 browser->b.seek(&browser->b, -offset, SEEK_CUR);
254 browser->b.top_idx = olrb->idx_asm - offset; 343 browser->b.top_idx = bdl->idx_asm - offset;
255 browser->b.index = olrb->idx_asm; 344 browser->b.index = bdl->idx_asm;
256 } 345 }
257 346
258 return true; 347 return true;
@@ -263,23 +352,16 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
263 void *arg, int delay_secs) 352 void *arg, int delay_secs)
264{ 353{
265 struct map_symbol *ms = browser->b.priv; 354 struct map_symbol *ms = browser->b.priv;
355 struct disasm_line *dl = browser->selection;
266 struct symbol *sym = ms->sym; 356 struct symbol *sym = ms->sym;
267 struct annotation *notes; 357 struct annotation *notes;
268 struct symbol *target; 358 struct symbol *target;
269 char *s = strstr(browser->selection->line, "callq ");
270 u64 ip; 359 u64 ip;
271 360
272 if (s == NULL) 361 if (!ins__is_call(dl->ins))
273 return false; 362 return false;
274 363
275 s = strchr(s, ' '); 364 ip = ms->map->map_ip(ms->map, dl->ops.target.addr);
276 if (s++ == NULL) {
277 ui_helpline__puts("Invallid callq instruction.");
278 return true;
279 }
280
281 ip = strtoull(s, NULL, 16);
282 ip = ms->map->map_ip(ms->map, ip);
283 target = map__find_symbol(ms->map, ip, NULL); 365 target = map__find_symbol(ms->map, ip, NULL);
284 if (target == NULL) { 366 if (target == NULL) {
285 ui_helpline__puts("The called function was not found."); 367 ui_helpline__puts("The called function was not found.");
@@ -302,20 +384,20 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
302 return true; 384 return true;
303} 385}
304 386
305static struct objdump_line * 387static
306 annotate_browser__find_offset(struct annotate_browser *browser, 388struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
307 s64 offset, s64 *idx) 389 s64 offset, s64 *idx)
308{ 390{
309 struct map_symbol *ms = browser->b.priv; 391 struct map_symbol *ms = browser->b.priv;
310 struct symbol *sym = ms->sym; 392 struct symbol *sym = ms->sym;
311 struct annotation *notes = symbol__annotation(sym); 393 struct annotation *notes = symbol__annotation(sym);
312 struct objdump_line *pos; 394 struct disasm_line *pos;
313 395
314 *idx = 0; 396 *idx = 0;
315 list_for_each_entry(pos, &notes->src->source, node) { 397 list_for_each_entry(pos, &notes->src->source, node) {
316 if (pos->offset == offset) 398 if (pos->offset == offset)
317 return pos; 399 return pos;
318 if (!objdump_line__filter(&browser->b, &pos->node)) 400 if (!disasm_line__filter(&browser->b, &pos->node))
319 ++*idx; 401 ++*idx;
320 } 402 }
321 403
@@ -324,51 +406,35 @@ static struct objdump_line *
324 406
325static bool annotate_browser__jump(struct annotate_browser *browser) 407static bool annotate_browser__jump(struct annotate_browser *browser)
326{ 408{
327 const char *jumps[] = { "je ", "jne ", "ja ", "jmpq ", "js ", "jmp ", NULL }; 409 struct disasm_line *dl = browser->selection;
328 struct objdump_line *line; 410 s64 idx;
329 s64 idx, offset;
330 char *s = NULL;
331 int i = 0;
332
333 while (jumps[i]) {
334 s = strstr(browser->selection->line, jumps[i++]);
335 if (s)
336 break;
337 }
338 411
339 if (s == NULL) 412 if (!ins__is_jump(dl->ins))
340 return false; 413 return false;
341 414
342 s = strchr(s, '+'); 415 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
343 if (s++ == NULL) { 416 if (dl == NULL) {
344 ui_helpline__puts("Invallid jump instruction.");
345 return true;
346 }
347
348 offset = strtoll(s, NULL, 16);
349 line = annotate_browser__find_offset(browser, offset, &idx);
350 if (line == NULL) {
351 ui_helpline__puts("Invallid jump offset"); 417 ui_helpline__puts("Invallid jump offset");
352 return true; 418 return true;
353 } 419 }
354 420
355 annotate_browser__set_top(browser, line, idx); 421 annotate_browser__set_top(browser, dl, idx);
356 422
357 return true; 423 return true;
358} 424}
359 425
360static struct objdump_line * 426static
361 annotate_browser__find_string(struct annotate_browser *browser, 427struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
362 char *s, s64 *idx) 428 char *s, s64 *idx)
363{ 429{
364 struct map_symbol *ms = browser->b.priv; 430 struct map_symbol *ms = browser->b.priv;
365 struct symbol *sym = ms->sym; 431 struct symbol *sym = ms->sym;
366 struct annotation *notes = symbol__annotation(sym); 432 struct annotation *notes = symbol__annotation(sym);
367 struct objdump_line *pos = browser->selection; 433 struct disasm_line *pos = browser->selection;
368 434
369 *idx = browser->b.index; 435 *idx = browser->b.index;
370 list_for_each_entry_continue(pos, &notes->src->source, node) { 436 list_for_each_entry_continue(pos, &notes->src->source, node) {
371 if (objdump_line__filter(&browser->b, &pos->node)) 437 if (disasm_line__filter(&browser->b, &pos->node))
372 continue; 438 continue;
373 439
374 ++*idx; 440 ++*idx;
@@ -382,32 +448,32 @@ static struct objdump_line *
382 448
383static bool __annotate_browser__search(struct annotate_browser *browser) 449static bool __annotate_browser__search(struct annotate_browser *browser)
384{ 450{
385 struct objdump_line *line; 451 struct disasm_line *dl;
386 s64 idx; 452 s64 idx;
387 453
388 line = annotate_browser__find_string(browser, browser->search_bf, &idx); 454 dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
389 if (line == NULL) { 455 if (dl == NULL) {
390 ui_helpline__puts("String not found!"); 456 ui_helpline__puts("String not found!");
391 return false; 457 return false;
392 } 458 }
393 459
394 annotate_browser__set_top(browser, line, idx); 460 annotate_browser__set_top(browser, dl, idx);
395 browser->searching_backwards = false; 461 browser->searching_backwards = false;
396 return true; 462 return true;
397} 463}
398 464
399static struct objdump_line * 465static
400 annotate_browser__find_string_reverse(struct annotate_browser *browser, 466struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
401 char *s, s64 *idx) 467 char *s, s64 *idx)
402{ 468{
403 struct map_symbol *ms = browser->b.priv; 469 struct map_symbol *ms = browser->b.priv;
404 struct symbol *sym = ms->sym; 470 struct symbol *sym = ms->sym;
405 struct annotation *notes = symbol__annotation(sym); 471 struct annotation *notes = symbol__annotation(sym);
406 struct objdump_line *pos = browser->selection; 472 struct disasm_line *pos = browser->selection;
407 473
408 *idx = browser->b.index; 474 *idx = browser->b.index;
409 list_for_each_entry_continue_reverse(pos, &notes->src->source, node) { 475 list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
410 if (objdump_line__filter(&browser->b, &pos->node)) 476 if (disasm_line__filter(&browser->b, &pos->node))
411 continue; 477 continue;
412 478
413 --*idx; 479 --*idx;
@@ -421,16 +487,16 @@ static struct objdump_line *
421 487
422static bool __annotate_browser__search_reverse(struct annotate_browser *browser) 488static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
423{ 489{
424 struct objdump_line *line; 490 struct disasm_line *dl;
425 s64 idx; 491 s64 idx;
426 492
427 line = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx); 493 dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
428 if (line == NULL) { 494 if (dl == NULL) {
429 ui_helpline__puts("String not found!"); 495 ui_helpline__puts("String not found!");
430 return false; 496 return false;
431 } 497 }
432 498
433 annotate_browser__set_top(browser, line, idx); 499 annotate_browser__set_top(browser, dl, idx);
434 browser->searching_backwards = true; 500 browser->searching_backwards = true;
435 return true; 501 return true;
436} 502}
@@ -581,9 +647,15 @@ show_help:
581 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org"); 647 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
582 else if (self->selection->offset == -1) 648 else if (self->selection->offset == -1)
583 ui_helpline__puts("Actions are only available for assembly lines."); 649 ui_helpline__puts("Actions are only available for assembly lines.");
584 else if (!(annotate_browser__jump(self) || 650 else if (!self->selection->ins) {
585 annotate_browser__callq(self, evidx, timer, arg, delay_secs))) 651 if (strcmp(self->selection->name, "retq"))
586 ui_helpline__puts("Actions are only available for the 'callq' and jump instructions."); 652 goto show_sup_ins;
653 goto out;
654 } else if (!(annotate_browser__jump(self) ||
655 annotate_browser__callq(self, evidx, timer, arg, delay_secs))) {
656show_sup_ins:
657 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
658 }
587 continue; 659 continue;
588 case K_LEFT: 660 case K_LEFT:
589 case K_ESC: 661 case K_ESC:
@@ -609,27 +681,63 @@ int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
609 timer, arg, delay_secs); 681 timer, arg, delay_secs);
610} 682}
611 683
684static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
685 size_t size)
686{
687 u64 offset;
688
689 for (offset = 0; offset < size; ++offset) {
690 struct disasm_line *dl = browser->offsets[offset], *dlt;
691 struct browser_disasm_line *bdlt;
692
693 if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
694 !disasm_line__has_offset(dl))
695 continue;
696
697 if (dl->ops.target.offset >= size) {
698 ui__error("jump to after symbol!\n"
699 "size: %zx, jump target: %" PRIx64,
700 size, dl->ops.target.offset);
701 continue;
702 }
703
704 dlt = browser->offsets[dl->ops.target.offset];
705 /*
706 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
707 * have to adjust to the previous offset?
708 */
709 if (dlt == NULL)
710 continue;
711
712 bdlt = disasm_line__browser(dlt);
713 bdlt->jump_target = true;
714 }
715
716}
717
612int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, 718int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
613 void(*timer)(void *arg), void *arg, 719 void(*timer)(void *arg), void *arg,
614 int delay_secs) 720 int delay_secs)
615{ 721{
616 struct objdump_line *pos, *n; 722 struct disasm_line *pos, *n;
617 struct annotation *notes; 723 struct annotation *notes;
724 const size_t size = symbol__size(sym);
618 struct map_symbol ms = { 725 struct map_symbol ms = {
619 .map = map, 726 .map = map,
620 .sym = sym, 727 .sym = sym,
621 }; 728 };
622 struct annotate_browser browser = { 729 struct annotate_browser browser = {
623 .b = { 730 .b = {
624 .refresh = ui_browser__list_head_refresh, 731 .refresh = annotate_browser__refresh,
625 .seek = ui_browser__list_head_seek, 732 .seek = ui_browser__list_head_seek,
626 .write = annotate_browser__write, 733 .write = annotate_browser__write,
627 .filter = objdump_line__filter, 734 .filter = disasm_line__filter,
628 .priv = &ms, 735 .priv = &ms,
629 .use_navkeypressed = true, 736 .use_navkeypressed = true,
630 }, 737 },
738 .use_offset = true,
631 }; 739 };
632 int ret; 740 int ret = -1;
633 741
634 if (sym == NULL) 742 if (sym == NULL)
635 return -1; 743 return -1;
@@ -637,37 +745,58 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
637 if (map->dso->annotate_warned) 745 if (map->dso->annotate_warned)
638 return -1; 746 return -1;
639 747
640 if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) { 748 browser.offsets = zalloc(size * sizeof(struct disasm_line *));
641 ui__error("%s", ui_helpline__last_msg); 749 if (browser.offsets == NULL) {
750 ui__error("Not enough memory!");
642 return -1; 751 return -1;
643 } 752 }
644 753
754 if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
755 ui__error("%s", ui_helpline__last_msg);
756 goto out_free_offsets;
757 }
758
645 ui_helpline__push("Press <- or ESC to exit"); 759 ui_helpline__push("Press <- or ESC to exit");
646 760
647 notes = symbol__annotation(sym); 761 notes = symbol__annotation(sym);
648 browser.start = map__rip_2objdump(map, sym->start); 762 browser.start = map__rip_2objdump(map, sym->start);
649 763
650 list_for_each_entry(pos, &notes->src->source, node) { 764 list_for_each_entry(pos, &notes->src->source, node) {
651 struct objdump_line_rb_node *rbpos; 765 struct browser_disasm_line *bpos;
652 size_t line_len = strlen(pos->line); 766 size_t line_len = strlen(pos->line);
653 767
654 if (browser.b.width < line_len) 768 if (browser.b.width < line_len)
655 browser.b.width = line_len; 769 browser.b.width = line_len;
656 rbpos = objdump_line__rb(pos); 770 bpos = disasm_line__browser(pos);
657 rbpos->idx = browser.nr_entries++; 771 bpos->idx = browser.nr_entries++;
658 if (pos->offset != -1) 772 if (pos->offset != -1) {
659 rbpos->idx_asm = browser.nr_asm_entries++; 773 bpos->idx_asm = browser.nr_asm_entries++;
660 else 774 /*
661 rbpos->idx_asm = -1; 775 * FIXME: short term bandaid to cope with assembly
776 * routines that comes with labels in the same column
777 * as the address in objdump, sigh.
778 *
779 * E.g. copy_user_generic_unrolled
780 */
781 if (pos->offset < (s64)size)
782 browser.offsets[pos->offset] = pos;
783 } else
784 bpos->idx_asm = -1;
662 } 785 }
663 786
787 annotate_browser__mark_jump_targets(&browser, size);
788
789 browser.offset_width = hex_width(size);
664 browser.b.nr_entries = browser.nr_entries; 790 browser.b.nr_entries = browser.nr_entries;
665 browser.b.entries = &notes->src->source, 791 browser.b.entries = &notes->src->source,
666 browser.b.width += 18; /* Percentage */ 792 browser.b.width += 18; /* Percentage */
667 ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs); 793 ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
668 list_for_each_entry_safe(pos, n, &notes->src->source, node) { 794 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
669 list_del(&pos->node); 795 list_del(&pos->node);
670 objdump_line__free(pos); 796 disasm_line__free(pos);
671 } 797 }
798
799out_free_offsets:
800 free(browser.offsets);
672 return ret; 801 return ret;
673} 802}
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 1e7fd52bd29d..5eb34123f55b 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -18,6 +18,149 @@
18 18
19const char *disassembler_style; 19const char *disassembler_style;
20 20
21static int call__parse(struct ins_operands *ops)
22{
23 char *endptr, *tok, *name;
24
25 ops->target.addr = strtoull(ops->raw, &endptr, 16);
26
27 name = strchr(endptr, '<');
28 if (name == NULL)
29 goto indirect_call;
30
31 name++;
32
33 tok = strchr(name, '>');
34 if (tok == NULL)
35 return -1;
36
37 *tok = '\0';
38 ops->target.name = strdup(name);
39 *tok = '>';
40
41 return ops->target.name == NULL ? -1 : 0;
42
43indirect_call:
44 tok = strchr(endptr, '*');
45 if (tok == NULL)
46 return -1;
47
48 ops->target.addr = strtoull(tok + 1, NULL, 16);
49 return 0;
50}
51
52static int call__scnprintf(struct ins *ins, char *bf, size_t size,
53 struct ins_operands *ops, bool addrs)
54{
55 if (addrs)
56 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw);
57
58 if (ops->target.name)
59 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name);
60
61 return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr);
62}
63
64static struct ins_ops call_ops = {
65 .parse = call__parse,
66 .scnprintf = call__scnprintf,
67};
68
69bool ins__is_call(const struct ins *ins)
70{
71 return ins->ops == &call_ops;
72}
73
74static int jump__parse(struct ins_operands *ops)
75{
76 const char *s = strchr(ops->raw, '+');
77
78 ops->target.addr = strtoll(ops->raw, NULL, 16);
79
80 if (s++ != NULL)
81 ops->target.offset = strtoll(s, NULL, 16);
82 else
83 ops->target.offset = UINT64_MAX;
84
85 return 0;
86}
87
88static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
89 struct ins_operands *ops, bool addrs)
90{
91 if (addrs)
92 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw);
93
94 return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset);
95}
96
97static struct ins_ops jump_ops = {
98 .parse = jump__parse,
99 .scnprintf = jump__scnprintf,
100};
101
102bool ins__is_jump(const struct ins *ins)
103{
104 return ins->ops == &jump_ops;
105}
106
107/*
108 * Must be sorted by name!
109 */
110static struct ins instructions[] = {
111 { .name = "call", .ops = &call_ops, },
112 { .name = "callq", .ops = &call_ops, },
113 { .name = "ja", .ops = &jump_ops, },
114 { .name = "jae", .ops = &jump_ops, },
115 { .name = "jb", .ops = &jump_ops, },
116 { .name = "jbe", .ops = &jump_ops, },
117 { .name = "jc", .ops = &jump_ops, },
118 { .name = "jcxz", .ops = &jump_ops, },
119 { .name = "je", .ops = &jump_ops, },
120 { .name = "jecxz", .ops = &jump_ops, },
121 { .name = "jg", .ops = &jump_ops, },
122 { .name = "jge", .ops = &jump_ops, },
123 { .name = "jl", .ops = &jump_ops, },
124 { .name = "jle", .ops = &jump_ops, },
125 { .name = "jmp", .ops = &jump_ops, },
126 { .name = "jmpq", .ops = &jump_ops, },
127 { .name = "jna", .ops = &jump_ops, },
128 { .name = "jnae", .ops = &jump_ops, },
129 { .name = "jnb", .ops = &jump_ops, },
130 { .name = "jnbe", .ops = &jump_ops, },
131 { .name = "jnc", .ops = &jump_ops, },
132 { .name = "jne", .ops = &jump_ops, },
133 { .name = "jng", .ops = &jump_ops, },
134 { .name = "jnge", .ops = &jump_ops, },
135 { .name = "jnl", .ops = &jump_ops, },
136 { .name = "jnle", .ops = &jump_ops, },
137 { .name = "jno", .ops = &jump_ops, },
138 { .name = "jnp", .ops = &jump_ops, },
139 { .name = "jns", .ops = &jump_ops, },
140 { .name = "jnz", .ops = &jump_ops, },
141 { .name = "jo", .ops = &jump_ops, },
142 { .name = "jp", .ops = &jump_ops, },
143 { .name = "jpe", .ops = &jump_ops, },
144 { .name = "jpo", .ops = &jump_ops, },
145 { .name = "jrcxz", .ops = &jump_ops, },
146 { .name = "js", .ops = &jump_ops, },
147 { .name = "jz", .ops = &jump_ops, },
148};
149
150static int ins__cmp(const void *name, const void *insp)
151{
152 const struct ins *ins = insp;
153
154 return strcmp(name, ins->name);
155}
156
157static struct ins *ins__find(const char *name)
158{
159 const int nmemb = ARRAY_SIZE(instructions);
160
161 return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp);
162}
163
21int symbol__annotate_init(struct map *map __used, struct symbol *sym) 164int symbol__annotate_init(struct map *map __used, struct symbol *sym)
22{ 165{
23 struct annotation *notes = symbol__annotation(sym); 166 struct annotation *notes = symbol__annotation(sym);
@@ -28,7 +171,7 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym)
28int symbol__alloc_hist(struct symbol *sym) 171int symbol__alloc_hist(struct symbol *sym)
29{ 172{
30 struct annotation *notes = symbol__annotation(sym); 173 struct annotation *notes = symbol__annotation(sym);
31 const size_t size = sym->end - sym->start + 1; 174 const size_t size = symbol__size(sym);
32 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); 175 size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
33 176
34 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); 177 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
@@ -78,36 +221,87 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
78 return 0; 221 return 0;
79} 222}
80 223
81static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize) 224static void disasm_line__init_ins(struct disasm_line *dl)
82{ 225{
83 struct objdump_line *self = malloc(sizeof(*self) + privsize); 226 dl->ins = ins__find(dl->name);
227
228 if (dl->ins == NULL)
229 return;
230
231 if (!dl->ins->ops)
232 return;
84 233
85 if (self != NULL) { 234 if (dl->ins->ops->parse)
86 self->offset = offset; 235 dl->ins->ops->parse(&dl->ops);
87 self->line = strdup(line); 236}
88 if (self->line == NULL) 237
238static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
239{
240 struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
241
242 if (dl != NULL) {
243 dl->offset = offset;
244 dl->line = strdup(line);
245 if (dl->line == NULL)
89 goto out_delete; 246 goto out_delete;
247
248 if (offset != -1) {
249 char *name = dl->line, tmp;
250
251 while (isspace(name[0]))
252 ++name;
253
254 if (name[0] == '\0')
255 goto out_delete;
256
257 dl->ops.raw = name + 1;
258
259 while (dl->ops.raw[0] != '\0' &&
260 !isspace(dl->ops.raw[0]))
261 ++dl->ops.raw;
262
263 tmp = dl->ops.raw[0];
264 dl->ops.raw[0] = '\0';
265 dl->name = strdup(name);
266
267 if (dl->name == NULL)
268 goto out_free_line;
269
270 dl->ops.raw[0] = tmp;
271
272 if (dl->ops.raw[0] != '\0') {
273 dl->ops.raw++;
274 while (isspace(dl->ops.raw[0]))
275 ++dl->ops.raw;
276 }
277
278 disasm_line__init_ins(dl);
279 }
90 } 280 }
91 281
92 return self; 282 return dl;
283
284out_free_line:
285 free(dl->line);
93out_delete: 286out_delete:
94 free(self); 287 free(dl);
95 return NULL; 288 return NULL;
96} 289}
97 290
98void objdump_line__free(struct objdump_line *self) 291void disasm_line__free(struct disasm_line *dl)
99{ 292{
100 free(self->line); 293 free(dl->line);
101 free(self); 294 free(dl->name);
295 free(dl->ops.target.name);
296 free(dl);
102} 297}
103 298
104static void objdump__add_line(struct list_head *head, struct objdump_line *line) 299static void disasm__add(struct list_head *head, struct disasm_line *line)
105{ 300{
106 list_add_tail(&line->node, head); 301 list_add_tail(&line->node, head);
107} 302}
108 303
109struct objdump_line *objdump__get_next_ip_line(struct list_head *head, 304struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos)
110 struct objdump_line *pos)
111{ 305{
112 list_for_each_entry_continue(pos, head, node) 306 list_for_each_entry_continue(pos, head, node)
113 if (pos->offset >= 0) 307 if (pos->offset >= 0)
@@ -116,15 +310,14 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
116 return NULL; 310 return NULL;
117} 311}
118 312
119static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, 313static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
120 u64 start, int evidx, u64 len, int min_pcnt, 314 int evidx, u64 len, int min_pcnt, int printed,
121 int printed, int max_lines, 315 int max_lines, struct disasm_line *queue)
122 struct objdump_line *queue)
123{ 316{
124 static const char *prev_line; 317 static const char *prev_line;
125 static const char *prev_color; 318 static const char *prev_color;
126 319
127 if (oline->offset != -1) { 320 if (dl->offset != -1) {
128 const char *path = NULL; 321 const char *path = NULL;
129 unsigned int hits = 0; 322 unsigned int hits = 0;
130 double percent = 0.0; 323 double percent = 0.0;
@@ -132,11 +325,11 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
132 struct annotation *notes = symbol__annotation(sym); 325 struct annotation *notes = symbol__annotation(sym);
133 struct source_line *src_line = notes->src->lines; 326 struct source_line *src_line = notes->src->lines;
134 struct sym_hist *h = annotation__histogram(notes, evidx); 327 struct sym_hist *h = annotation__histogram(notes, evidx);
135 s64 offset = oline->offset; 328 s64 offset = dl->offset;
136 const u64 addr = start + offset; 329 const u64 addr = start + offset;
137 struct objdump_line *next; 330 struct disasm_line *next;
138 331
139 next = objdump__get_next_ip_line(&notes->src->source, oline); 332 next = disasm__get_next_ip_line(&notes->src->source, dl);
140 333
141 while (offset < (s64)len && 334 while (offset < (s64)len &&
142 (next == NULL || offset < next->offset)) { 335 (next == NULL || offset < next->offset)) {
@@ -161,9 +354,9 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
161 354
162 if (queue != NULL) { 355 if (queue != NULL) {
163 list_for_each_entry_from(queue, &notes->src->source, node) { 356 list_for_each_entry_from(queue, &notes->src->source, node) {
164 if (queue == oline) 357 if (queue == dl)
165 break; 358 break;
166 objdump_line__print(queue, sym, start, evidx, len, 359 disasm_line__print(queue, sym, start, evidx, len,
167 0, 0, 1, NULL); 360 0, 0, 1, NULL);
168 } 361 }
169 } 362 }
@@ -187,17 +380,17 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
187 color_fprintf(stdout, color, " %7.2f", percent); 380 color_fprintf(stdout, color, " %7.2f", percent);
188 printf(" : "); 381 printf(" : ");
189 color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); 382 color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr);
190 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line); 383 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
191 } else if (max_lines && printed >= max_lines) 384 } else if (max_lines && printed >= max_lines)
192 return 1; 385 return 1;
193 else { 386 else {
194 if (queue) 387 if (queue)
195 return -1; 388 return -1;
196 389
197 if (!*oline->line) 390 if (!*dl->line)
198 printf(" :\n"); 391 printf(" :\n");
199 else 392 else
200 printf(" : %s\n", oline->line); 393 printf(" : %s\n", dl->line);
201 } 394 }
202 395
203 return 0; 396 return 0;
@@ -207,7 +400,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
207 FILE *file, size_t privsize) 400 FILE *file, size_t privsize)
208{ 401{
209 struct annotation *notes = symbol__annotation(sym); 402 struct annotation *notes = symbol__annotation(sym);
210 struct objdump_line *objdump_line; 403 struct disasm_line *dl;
211 char *line = NULL, *parsed_line, *tmp, *tmp2, *c; 404 char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
212 size_t line_len; 405 size_t line_len;
213 s64 line_ip, offset = -1; 406 s64 line_ip, offset = -1;
@@ -258,13 +451,13 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
258 parsed_line = tmp2 + 1; 451 parsed_line = tmp2 + 1;
259 } 452 }
260 453
261 objdump_line = objdump_line__new(offset, parsed_line, privsize); 454 dl = disasm_line__new(offset, parsed_line, privsize);
262 free(line); 455 free(line);
263 456
264 if (objdump_line == NULL) 457 if (dl == NULL)
265 return -1; 458 return -1;
266 459
267 objdump__add_line(&notes->src->source, objdump_line); 460 disasm__add(&notes->src->source, dl);
268 461
269 return 0; 462 return 0;
270} 463}
@@ -487,7 +680,7 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx)
487{ 680{
488 struct annotation *notes = symbol__annotation(sym); 681 struct annotation *notes = symbol__annotation(sym);
489 struct sym_hist *h = annotation__histogram(notes, evidx); 682 struct sym_hist *h = annotation__histogram(notes, evidx);
490 u64 len = sym->end - sym->start, offset; 683 u64 len = symbol__size(sym), offset;
491 684
492 for (offset = 0; offset < len; ++offset) 685 for (offset = 0; offset < len; ++offset)
493 if (h->addr[offset] != 0) 686 if (h->addr[offset] != 0)
@@ -503,7 +696,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
503 struct dso *dso = map->dso; 696 struct dso *dso = map->dso;
504 const char *filename = dso->long_name, *d_filename; 697 const char *filename = dso->long_name, *d_filename;
505 struct annotation *notes = symbol__annotation(sym); 698 struct annotation *notes = symbol__annotation(sym);
506 struct objdump_line *pos, *queue = NULL; 699 struct disasm_line *pos, *queue = NULL;
507 u64 start = map__rip_2objdump(map, sym->start); 700 u64 start = map__rip_2objdump(map, sym->start);
508 int printed = 2, queue_len = 0; 701 int printed = 2, queue_len = 0;
509 int more = 0; 702 int more = 0;
@@ -514,7 +707,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
514 else 707 else
515 d_filename = basename(filename); 708 d_filename = basename(filename);
516 709
517 len = sym->end - sym->start; 710 len = symbol__size(sym);
518 711
519 printf(" Percent | Source code & Disassembly of %s\n", d_filename); 712 printf(" Percent | Source code & Disassembly of %s\n", d_filename);
520 printf("------------------------------------------------\n"); 713 printf("------------------------------------------------\n");
@@ -528,7 +721,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
528 queue_len = 0; 721 queue_len = 0;
529 } 722 }
530 723
531 switch (objdump_line__print(pos, sym, start, evidx, len, 724 switch (disasm_line__print(pos, sym, start, evidx, len,
532 min_pcnt, printed, max_lines, 725 min_pcnt, printed, max_lines,
533 queue)) { 726 queue)) {
534 case 0: 727 case 0:
@@ -574,7 +767,7 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
574{ 767{
575 struct annotation *notes = symbol__annotation(sym); 768 struct annotation *notes = symbol__annotation(sym);
576 struct sym_hist *h = annotation__histogram(notes, evidx); 769 struct sym_hist *h = annotation__histogram(notes, evidx);
577 int len = sym->end - sym->start, offset; 770 int len = symbol__size(sym), offset;
578 771
579 h->sum = 0; 772 h->sum = 0;
580 for (offset = 0; offset < len; ++offset) { 773 for (offset = 0; offset < len; ++offset) {
@@ -583,14 +776,42 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
583 } 776 }
584} 777}
585 778
586void objdump_line_list__purge(struct list_head *head) 779void disasm__purge(struct list_head *head)
587{ 780{
588 struct objdump_line *pos, *n; 781 struct disasm_line *pos, *n;
589 782
590 list_for_each_entry_safe(pos, n, head, node) { 783 list_for_each_entry_safe(pos, n, head, node) {
591 list_del(&pos->node); 784 list_del(&pos->node);
592 objdump_line__free(pos); 785 disasm_line__free(pos);
786 }
787}
788
789static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
790{
791 size_t printed;
792
793 if (dl->offset == -1)
794 return fprintf(fp, "%s\n", dl->line);
795
796 printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name);
797
798 if (dl->ops.raw[0] != '\0') {
799 printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
800 dl->ops.raw);
593 } 801 }
802
803 return printed + fprintf(fp, "\n");
804}
805
806size_t disasm__fprintf(struct list_head *head, FILE *fp)
807{
808 struct disasm_line *pos;
809 size_t printed = 0;
810
811 list_for_each_entry(pos, head, node)
812 printed += disasm_line__fprintf(pos, fp);
813
814 return printed;
594} 815}
595 816
596int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 817int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
@@ -605,7 +826,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
605 if (symbol__annotate(sym, map, 0) < 0) 826 if (symbol__annotate(sym, map, 0) < 0)
606 return -1; 827 return -1;
607 828
608 len = sym->end - sym->start; 829 len = symbol__size(sym);
609 830
610 if (print_lines) { 831 if (print_lines) {
611 symbol__get_source_line(sym, map, evidx, &source_line, 832 symbol__get_source_line(sym, map, evidx, &source_line,
@@ -618,7 +839,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
618 if (print_lines) 839 if (print_lines)
619 symbol__free_source_line(sym, len); 840 symbol__free_source_line(sym, len);
620 841
621 objdump_line_list__purge(&symbol__annotation(sym)->src->source); 842 disasm__purge(&symbol__annotation(sym)->src->source);
622 843
623 return 0; 844 return 0;
624} 845}
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index efa5dc82bfae..13a21f10dabb 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -2,20 +2,54 @@
2#define __PERF_ANNOTATE_H 2#define __PERF_ANNOTATE_H
3 3
4#include <stdbool.h> 4#include <stdbool.h>
5#include <stdint.h>
5#include "types.h" 6#include "types.h"
6#include "symbol.h" 7#include "symbol.h"
7#include <linux/list.h> 8#include <linux/list.h>
8#include <linux/rbtree.h> 9#include <linux/rbtree.h>
9 10
10struct objdump_line { 11struct ins;
11 struct list_head node; 12
12 s64 offset; 13struct ins_operands {
13 char *line; 14 char *raw;
15 struct {
16 char *name;
17 u64 offset;
18 u64 addr;
19 } target;
20};
21
22struct ins_ops {
23 int (*parse)(struct ins_operands *ops);
24 int (*scnprintf)(struct ins *ins, char *bf, size_t size,
25 struct ins_operands *ops, bool addrs);
14}; 26};
15 27
16void objdump_line__free(struct objdump_line *self); 28struct ins {
17struct objdump_line *objdump__get_next_ip_line(struct list_head *head, 29 const char *name;
18 struct objdump_line *pos); 30 struct ins_ops *ops;
31};
32
33bool ins__is_jump(const struct ins *ins);
34bool ins__is_call(const struct ins *ins);
35
36struct disasm_line {
37 struct list_head node;
38 s64 offset;
39 char *line;
40 char *name;
41 struct ins *ins;
42 struct ins_operands ops;
43};
44
45static inline bool disasm_line__has_offset(const struct disasm_line *dl)
46{
47 return dl->ops.target.offset != UINT64_MAX;
48}
49
50void disasm_line__free(struct disasm_line *dl);
51struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos);
52size_t disasm__fprintf(struct list_head *head, FILE *fp);
19 53
20struct sym_hist { 54struct sym_hist {
21 u64 sum; 55 u64 sum;
@@ -32,7 +66,7 @@ struct source_line {
32 * 66 *
33 * @histogram: Array of addr hit histograms per event being monitored 67 * @histogram: Array of addr hit histograms per event being monitored
34 * @lines: If 'print_lines' is specified, per source code line percentages 68 * @lines: If 'print_lines' is specified, per source code line percentages
35 * @source: source parsed from objdump -dS 69 * @source: source parsed from a disassembler like objdump -dS
36 * 70 *
37 * lines is allocated, percentages calculated and all sorted by percentage 71 * lines is allocated, percentages calculated and all sorted by percentage
38 * when the annotation is about to be presented, so the percentages are for 72 * when the annotation is about to be presented, so the percentages are for
@@ -82,7 +116,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
82 int context); 116 int context);
83void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); 117void symbol__annotate_zero_histogram(struct symbol *sym, int evidx);
84void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); 118void symbol__annotate_decay_histogram(struct symbol *sym, int evidx);
85void objdump_line_list__purge(struct list_head *head); 119void disasm__purge(struct list_head *head);
86 120
87int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, 121int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
88 bool print_lines, bool full_paths, int min_pcnt, 122 bool print_lines, bool full_paths, int min_pcnt,
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 {
65 65
66void symbol__delete(struct symbol *sym); 66void symbol__delete(struct symbol *sym);
67 67
68static inline size_t symbol__size(const struct symbol *sym)
69{
70 return sym->end - sym->start + 1;
71}
72
68struct strlist; 73struct strlist;
69 74
70struct symbol_conf { 75struct symbol_conf {
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)
148 148
149 return buf - buf_start; 149 return buf - buf_start;
150} 150}
151
152size_t hex_width(u64 v)
153{
154 size_t n = 1;
155
156 while ((v >>= 4))
157 ++n;
158
159 return n;
160}
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)
265 return (n != 0 && ((n & (n - 1)) == 0)); 265 return (n != 0 && ((n & (n - 1)) == 0));
266} 266}
267 267
268size_t hex_width(u64 v);
269
268#endif 270#endif