]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - tools/perf/ui/browsers/annotate.c
perf annotate: Remove duplicate 'name' field from disasm_line
[mirror_ubuntu-zesty-kernel.git] / tools / perf / ui / browsers / annotate.c
CommitLineData
aca7a94d 1#include "../../util/util.h"
211ef127
ACM
2#include "../browser.h"
3#include "../helpline.h"
ae55795e
ACM
4#include "../ui.h"
5#include "../util.h"
aca7a94d
NK
6#include "../../util/annotate.h"
7#include "../../util/hist.h"
8#include "../../util/sort.h"
9#include "../../util/symbol.h"
db8fd07a 10#include "../../util/evsel.h"
41840d21 11#include "../../util/config.h"
c97cf422 12#include <pthread.h>
211ef127 13
0c4a5bce
ML
14struct disasm_line_samples {
15 double percent;
16 u64 nr;
17};
18
f8f4aaea
AK
19#define IPC_WIDTH 6
20#define CYCLES_WIDTH 6
21
b793a401 22struct browser_disasm_line {
0c4a5bce
ML
23 struct rb_node rb_node;
24 u32 idx;
25 int idx_asm;
26 int jump_sources;
c7e7b610
NK
27 /*
28 * actual length of this array is saved on the nr_events field
29 * of the struct annotate_browser
30 */
0c4a5bce 31 struct disasm_line_samples samples[1];
b793a401
ACM
32};
33
e9823b21
ACM
34static struct annotate_browser_opt {
35 bool hide_src_code,
36 use_offset,
37 jump_arrows,
e592488c 38 show_linenr,
0c4a5bce
ML
39 show_nr_jumps,
40 show_total_period;
e9823b21
ACM
41} annotate_browser__opts = {
42 .use_offset = true,
43 .jump_arrows = true,
44};
45
92221162
ACM
46struct annotate_browser {
47 struct ui_browser b;
48 struct rb_root entries;
f1e9214c 49 struct rb_node *curr_hot;
c7e7b610 50 struct disasm_line *selection;
b793a401 51 struct disasm_line **offsets;
c7e7b610 52 int nr_events;
058b4cc9 53 u64 start;
0361fc25
ACM
54 int nr_asm_entries;
55 int nr_entries;
2402e4a9
ACM
56 int max_jump_sources;
57 int nr_jumps;
d3d1f61a 58 bool searching_backwards;
30e863bb 59 bool have_cycles;
83b1f2aa 60 u8 addr_width;
2402e4a9
ACM
61 u8 jumps_width;
62 u8 target_width;
83b1f2aa
ACM
63 u8 min_addr_width;
64 u8 max_addr_width;
d3d1f61a 65 char search_bf[128];
92221162
ACM
66};
67
887c0066 68static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
92221162 69{
887c0066 70 return (struct browser_disasm_line *)(dl + 1);
92221162
ACM
71}
72
1d037ca1
IT
73static bool disasm_line__filter(struct ui_browser *browser __maybe_unused,
74 void *entry)
0361fc25 75{
e9823b21 76 if (annotate_browser__opts.hide_src_code) {
29ed6e76
ACM
77 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
78 return dl->offset == -1;
0361fc25
ACM
79 }
80
81 return false;
82}
83
2402e4a9
ACM
84static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
85 int nr, bool current)
86{
87 if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
88 return HE_COLORSET_SELECTED;
89 if (nr == browser->max_jump_sources)
90 return HE_COLORSET_TOP;
91 if (nr > 1)
92 return HE_COLORSET_MEDIUM;
93 return HE_COLORSET_NORMAL;
94}
95
96static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
97 int nr, bool current)
98{
99 int color = annotate_browser__jumps_percent_color(browser, nr, current);
100 return ui_browser__set_color(&browser->b, color);
101}
102
f8f4aaea
AK
103static int annotate_browser__pcnt_width(struct annotate_browser *ab)
104{
105 int w = 7 * ab->nr_events;
106
107 if (ab->have_cycles)
108 w += IPC_WIDTH + CYCLES_WIDTH;
109 return w;
110}
111
05e8b080 112static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
211ef127 113{
05e8b080 114 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
29ed6e76 115 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
b793a401 116 struct browser_disasm_line *bdl = disasm_line__browser(dl);
05e8b080 117 bool current_entry = ui_browser__is_current_entry(browser, row);
e9823b21 118 bool change_color = (!annotate_browser__opts.hide_src_code &&
05e8b080
ACM
119 (!current_entry || (browser->use_navkeypressed &&
120 !browser->navkeypressed)));
121 int width = browser->width, printed;
f8f4aaea 122 int i, pcnt_width = annotate_browser__pcnt_width(ab);
c7e7b610 123 double percent_max = 0.0;
83b1f2aa 124 char bf[256];
211ef127 125
c7e7b610 126 for (i = 0; i < ab->nr_events; i++) {
0c4a5bce
ML
127 if (bdl->samples[i].percent > percent_max)
128 percent_max = bdl->samples[i].percent;
c7e7b610
NK
129 }
130
131 if (dl->offset != -1 && percent_max != 0.0) {
f8f4aaea
AK
132 if (percent_max != 0.0) {
133 for (i = 0; i < ab->nr_events; i++) {
134 ui_browser__set_percent_color(browser,
135 bdl->samples[i].percent,
136 current_entry);
517dfdb3
ACM
137 if (annotate_browser__opts.show_total_period) {
138 ui_browser__printf(browser, "%6" PRIu64 " ",
139 bdl->samples[i].nr);
140 } else {
141 ui_browser__printf(browser, "%6.2f ",
142 bdl->samples[i].percent);
143 }
f8f4aaea
AK
144 }
145 } else {
26270a00 146 ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
c7e7b610 147 }
92221162 148 } else {
05e8b080 149 ui_browser__set_percent_color(browser, 0, current_entry);
26270a00 150 ui_browser__write_nstring(browser, " ", 7 * ab->nr_events);
f8f4aaea
AK
151 }
152 if (ab->have_cycles) {
153 if (dl->ipc)
517dfdb3 154 ui_browser__printf(browser, "%*.2f ", IPC_WIDTH - 1, dl->ipc);
f8f4aaea 155 else
26270a00 156 ui_browser__write_nstring(browser, " ", IPC_WIDTH);
f8f4aaea 157 if (dl->cycles)
517dfdb3
ACM
158 ui_browser__printf(browser, "%*" PRIu64 " ",
159 CYCLES_WIDTH - 1, dl->cycles);
f8f4aaea 160 else
26270a00 161 ui_browser__write_nstring(browser, " ", CYCLES_WIDTH);
92221162
ACM
162 }
163
cf2dacc5 164 SLsmg_write_char(' ');
c172f742
ACM
165
166 /* The scroll bar isn't being used */
05e8b080 167 if (!browser->navkeypressed)
c172f742
ACM
168 width += 1;
169
29ed6e76 170 if (!*dl->line)
26270a00 171 ui_browser__write_nstring(browser, " ", width - pcnt_width);
83b1f2aa 172 else if (dl->offset == -1) {
e592488c
AK
173 if (dl->line_nr && annotate_browser__opts.show_linenr)
174 printed = scnprintf(bf, sizeof(bf), "%-*d ",
175 ab->addr_width + 1, dl->line_nr);
176 else
177 printed = scnprintf(bf, sizeof(bf), "%*s ",
83b1f2aa 178 ab->addr_width, " ");
26270a00
ACM
179 ui_browser__write_nstring(browser, bf, printed);
180 ui_browser__write_nstring(browser, dl->line, width - printed - pcnt_width + 1);
83b1f2aa 181 } else {
29ed6e76 182 u64 addr = dl->offset;
83b1f2aa 183 int color = -1;
058b4cc9 184
e9823b21 185 if (!annotate_browser__opts.use_offset)
e235f3f3
ACM
186 addr += ab->start;
187
e9823b21 188 if (!annotate_browser__opts.use_offset) {
83b1f2aa 189 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
61e04b33 190 } else {
7d5b12f5 191 if (bdl->jump_sources) {
e9823b21 192 if (annotate_browser__opts.show_nr_jumps) {
2402e4a9
ACM
193 int prev;
194 printed = scnprintf(bf, sizeof(bf), "%*d ",
195 ab->jumps_width,
196 bdl->jump_sources);
197 prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
198 current_entry);
26270a00 199 ui_browser__write_nstring(browser, bf, printed);
05e8b080 200 ui_browser__set_color(browser, prev);
2402e4a9
ACM
201 }
202
83b1f2aa 203 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
2402e4a9 204 ab->target_width, addr);
61e04b33 205 } else {
83b1f2aa
ACM
206 printed = scnprintf(bf, sizeof(bf), "%*s ",
207 ab->addr_width, " ");
61e04b33
ACM
208 }
209 }
b793a401 210
058b4cc9 211 if (change_color)
05e8b080 212 color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
26270a00 213 ui_browser__write_nstring(browser, bf, printed);
058b4cc9 214 if (change_color)
05e8b080 215 ui_browser__set_color(browser, color);
75b49202
ACM
216 if (dl->ins.ops && dl->ins.ops->scnprintf) {
217 if (ins__is_jump(&dl->ins)) {
44d1a3ed 218 bool fwd = dl->ops.target.offset > (u64)dl->offset;
51a0d455 219
05e8b080 220 ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
59d038d5 221 SLSMG_UARROW_CHAR);
51a0d455 222 SLsmg_write_char(' ');
75b49202 223 } else if (ins__is_call(&dl->ins)) {
05e8b080 224 ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
88298f5a 225 SLsmg_write_char(' ');
75b49202 226 } else if (ins__is_ret(&dl->ins)) {
6ef94929
NR
227 ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
228 SLsmg_write_char(' ');
51a0d455 229 } else {
26270a00 230 ui_browser__write_nstring(browser, " ", 2);
51a0d455 231 }
4ea08b52 232 } else {
6ef94929 233 ui_browser__write_nstring(browser, " ", 2);
4ea08b52 234 }
28548d78 235
e9823b21 236 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
26270a00 237 ui_browser__write_nstring(browser, bf, width - pcnt_width - 3 - printed);
058b4cc9 238 }
b99976e2 239
58e817d9 240 if (current_entry)
29ed6e76 241 ab->selection = dl;
92221162
ACM
242}
243
865c66c4
FD
244static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym)
245{
75b49202 246 if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins)
865c66c4
FD
247 || !disasm_line__has_offset(dl)
248 || dl->ops.target.offset >= symbol__size(sym))
249 return false;
250
251 return true;
252}
253
9d1ef56d 254static void annotate_browser__draw_current_jump(struct ui_browser *browser)
a3f895be
ACM
255{
256 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
9d1ef56d
ACM
257 struct disasm_line *cursor = ab->selection, *target;
258 struct browser_disasm_line *btarget, *bcursor;
83b1f2aa 259 unsigned int from, to;
32ae1efd
NK
260 struct map_symbol *ms = ab->b.priv;
261 struct symbol *sym = ms->sym;
f8f4aaea 262 u8 pcnt_width = annotate_browser__pcnt_width(ab);
32ae1efd
NK
263
264 /* PLT symbols contain external offsets */
265 if (strstr(sym->name, "@plt"))
266 return;
a3f895be 267
865c66c4 268 if (!disasm_line__is_valid_jump(cursor, sym))
9d1ef56d 269 return;
a3f895be 270
9d1ef56d
ACM
271 target = ab->offsets[cursor->ops.target.offset];
272 if (!target)
273 return;
a3f895be 274
9d1ef56d
ACM
275 bcursor = disasm_line__browser(cursor);
276 btarget = disasm_line__browser(target);
a3f895be 277
e9823b21 278 if (annotate_browser__opts.hide_src_code) {
9d1ef56d 279 from = bcursor->idx_asm;
a3f895be
ACM
280 to = btarget->idx_asm;
281 } else {
9d1ef56d 282 from = (u64)bcursor->idx;
a3f895be
ACM
283 to = (u64)btarget->idx;
284 }
285
78ce08df 286 ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
c7e7b610
NK
287 __ui_browser__line_arrow(browser, pcnt_width + 2 + ab->addr_width,
288 from, to);
a3f895be
ACM
289}
290
291static unsigned int annotate_browser__refresh(struct ui_browser *browser)
292{
c7e7b610 293 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
a3f895be 294 int ret = ui_browser__list_head_refresh(browser);
f8f4aaea 295 int pcnt_width = annotate_browser__pcnt_width(ab);
a3f895be 296
e9823b21 297 if (annotate_browser__opts.jump_arrows)
9d1ef56d 298 annotate_browser__draw_current_jump(browser);
a3f895be 299
83b1f2aa 300 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
c7e7b610 301 __ui_browser__vline(browser, pcnt_width, 0, browser->height - 1);
a3f895be
ACM
302 return ret;
303}
304
c7e7b610
NK
305static int disasm__cmp(struct browser_disasm_line *a,
306 struct browser_disasm_line *b, int nr_pcnt)
307{
308 int i;
309
310 for (i = 0; i < nr_pcnt; i++) {
0c4a5bce 311 if (a->samples[i].percent == b->samples[i].percent)
c7e7b610 312 continue;
0c4a5bce 313 return a->samples[i].percent < b->samples[i].percent;
c7e7b610
NK
314 }
315 return 0;
316}
317
318static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl,
319 int nr_events)
92221162 320{
29ed6e76 321 struct rb_node **p = &root->rb_node;
92221162 322 struct rb_node *parent = NULL;
887c0066 323 struct browser_disasm_line *l;
92221162
ACM
324
325 while (*p != NULL) {
326 parent = *p;
887c0066 327 l = rb_entry(parent, struct browser_disasm_line, rb_node);
c7e7b610
NK
328
329 if (disasm__cmp(bdl, l, nr_events))
92221162
ACM
330 p = &(*p)->rb_left;
331 else
332 p = &(*p)->rb_right;
333 }
887c0066
ACM
334 rb_link_node(&bdl->rb_node, parent, p);
335 rb_insert_color(&bdl->rb_node, root);
211ef127
ACM
336}
337
05e8b080 338static void annotate_browser__set_top(struct annotate_browser *browser,
29ed6e76 339 struct disasm_line *pos, u32 idx)
f1e9214c 340{
f1e9214c
ACM
341 unsigned back;
342
05e8b080
ACM
343 ui_browser__refresh_dimensions(&browser->b);
344 back = browser->b.height / 2;
345 browser->b.top_idx = browser->b.index = idx;
f1e9214c 346
05e8b080 347 while (browser->b.top_idx != 0 && back != 0) {
29ed6e76 348 pos = list_entry(pos->node.prev, struct disasm_line, node);
f1e9214c 349
05e8b080 350 if (disasm_line__filter(&browser->b, &pos->node))
08be4eed
ACM
351 continue;
352
05e8b080 353 --browser->b.top_idx;
f1e9214c
ACM
354 --back;
355 }
356
05e8b080
ACM
357 browser->b.top = pos;
358 browser->b.navkeypressed = true;
b0ffb2c4
ACM
359}
360
361static void annotate_browser__set_rb_top(struct annotate_browser *browser,
362 struct rb_node *nd)
363{
887c0066 364 struct browser_disasm_line *bpos;
29ed6e76 365 struct disasm_line *pos;
a44b45f2 366 u32 idx;
b0ffb2c4 367
887c0066
ACM
368 bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
369 pos = ((struct disasm_line *)bpos) - 1;
a44b45f2 370 idx = bpos->idx;
e9823b21 371 if (annotate_browser__opts.hide_src_code)
a44b45f2
ACM
372 idx = bpos->idx_asm;
373 annotate_browser__set_top(browser, pos, idx);
b0ffb2c4 374 browser->curr_hot = nd;
f1e9214c
ACM
375}
376
c97cf422 377static void annotate_browser__calc_percent(struct annotate_browser *browser,
db8fd07a 378 struct perf_evsel *evsel)
f1e9214c 379{
34958544
ACM
380 struct map_symbol *ms = browser->b.priv;
381 struct symbol *sym = ms->sym;
c97cf422 382 struct annotation *notes = symbol__annotation(sym);
e64aa75b
NK
383 struct disasm_line *pos, *next;
384 s64 len = symbol__size(sym);
c97cf422
ACM
385
386 browser->entries = RB_ROOT;
387
388 pthread_mutex_lock(&notes->lock);
389
390 list_for_each_entry(pos, &notes->src->source, node) {
887c0066 391 struct browser_disasm_line *bpos = disasm_line__browser(pos);
e64aa75b 392 const char *path = NULL;
c7e7b610
NK
393 double max_percent = 0.0;
394 int i;
e64aa75b
NK
395
396 if (pos->offset == -1) {
397 RB_CLEAR_NODE(&bpos->rb_node);
398 continue;
399 }
400
401 next = disasm__get_next_ip_line(&notes->src->source, pos);
e64aa75b 402
c7e7b610 403 for (i = 0; i < browser->nr_events; i++) {
0c4a5bce
ML
404 u64 nr_samples;
405
406 bpos->samples[i].percent = disasm__calc_percent(notes,
c7e7b610
NK
407 evsel->idx + i,
408 pos->offset,
409 next ? next->offset : len,
0c4a5bce
ML
410 &path, &nr_samples);
411 bpos->samples[i].nr = nr_samples;
c7e7b610 412
0c4a5bce
ML
413 if (max_percent < bpos->samples[i].percent)
414 max_percent = bpos->samples[i].percent;
c7e7b610
NK
415 }
416
30e863bb 417 if (max_percent < 0.01 && pos->ipc == 0) {
887c0066 418 RB_CLEAR_NODE(&bpos->rb_node);
c97cf422
ACM
419 continue;
420 }
c7e7b610
NK
421 disasm_rb_tree__insert(&browser->entries, bpos,
422 browser->nr_events);
c97cf422
ACM
423 }
424 pthread_mutex_unlock(&notes->lock);
425
426 browser->curr_hot = rb_last(&browser->entries);
427}
428
0361fc25
ACM
429static bool annotate_browser__toggle_source(struct annotate_browser *browser)
430{
29ed6e76 431 struct disasm_line *dl;
887c0066 432 struct browser_disasm_line *bdl;
0361fc25
ACM
433 off_t offset = browser->b.index - browser->b.top_idx;
434
435 browser->b.seek(&browser->b, offset, SEEK_CUR);
29ed6e76 436 dl = list_entry(browser->b.top, struct disasm_line, node);
887c0066 437 bdl = disasm_line__browser(dl);
0361fc25 438
e9823b21 439 if (annotate_browser__opts.hide_src_code) {
887c0066
ACM
440 if (bdl->idx_asm < offset)
441 offset = bdl->idx;
0361fc25
ACM
442
443 browser->b.nr_entries = browser->nr_entries;
e9823b21 444 annotate_browser__opts.hide_src_code = false;
0361fc25 445 browser->b.seek(&browser->b, -offset, SEEK_CUR);
887c0066
ACM
446 browser->b.top_idx = bdl->idx - offset;
447 browser->b.index = bdl->idx;
0361fc25 448 } else {
887c0066 449 if (bdl->idx_asm < 0) {
0361fc25
ACM
450 ui_helpline__puts("Only available for assembly lines.");
451 browser->b.seek(&browser->b, -offset, SEEK_CUR);
452 return false;
453 }
454
887c0066
ACM
455 if (bdl->idx_asm < offset)
456 offset = bdl->idx_asm;
0361fc25
ACM
457
458 browser->b.nr_entries = browser->nr_asm_entries;
e9823b21 459 annotate_browser__opts.hide_src_code = true;
0361fc25 460 browser->b.seek(&browser->b, -offset, SEEK_CUR);
887c0066
ACM
461 browser->b.top_idx = bdl->idx_asm - offset;
462 browser->b.index = bdl->idx_asm;
0361fc25
ACM
463 }
464
465 return true;
466}
467
e9823b21
ACM
468static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
469{
470 ui_browser__reset_index(&browser->b);
471 browser->b.nr_entries = browser->nr_asm_entries;
472}
473
34f77abc
AH
474#define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
475
476static int sym_title(struct symbol *sym, struct map *map, char *title,
477 size_t sz)
478{
479 return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name);
480}
481
db8fd07a
NK
482static bool annotate_browser__callq(struct annotate_browser *browser,
483 struct perf_evsel *evsel,
9783adf7 484 struct hist_browser_timer *hbt)
60521702
ACM
485{
486 struct map_symbol *ms = browser->b.priv;
657bcaf5 487 struct disasm_line *dl = browser->selection;
60521702 488 struct annotation *notes;
1179e11b
AH
489 struct addr_map_symbol target = {
490 .map = ms->map,
1d5077bd 491 .addr = map__objdump_2mem(ms->map, dl->ops.target.addr),
1179e11b 492 };
34f77abc 493 char title[SYM_TITLE_MAX_SIZE];
60521702 494
75b49202 495 if (!ins__is_call(&dl->ins))
60521702
ACM
496 return false;
497
be39db9f 498 if (map_groups__find_ams(&target) ||
1d5077bd
AH
499 map__rip_2objdump(target.map, target.map->map_ip(target.map,
500 target.addr)) !=
501 dl->ops.target.addr) {
60521702
ACM
502 ui_helpline__puts("The called function was not found.");
503 return true;
504 }
505
1179e11b 506 notes = symbol__annotation(target.sym);
60521702
ACM
507 pthread_mutex_lock(&notes->lock);
508
1179e11b 509 if (notes->src == NULL && symbol__alloc_hist(target.sym) < 0) {
60521702
ACM
510 pthread_mutex_unlock(&notes->lock);
511 ui__warning("Not enough memory for annotating '%s' symbol!\n",
1179e11b 512 target.sym->name);
60521702
ACM
513 return true;
514 }
515
516 pthread_mutex_unlock(&notes->lock);
1179e11b
AH
517 symbol__tui_annotate(target.sym, target.map, evsel, hbt);
518 sym_title(ms->sym, ms->map, title, sizeof(title));
34f77abc 519 ui_browser__show_title(&browser->b, title);
60521702
ACM
520 return true;
521}
522
29ed6e76
ACM
523static
524struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
525 s64 offset, s64 *idx)
08be4eed
ACM
526{
527 struct map_symbol *ms = browser->b.priv;
528 struct symbol *sym = ms->sym;
529 struct annotation *notes = symbol__annotation(sym);
29ed6e76 530 struct disasm_line *pos;
08be4eed
ACM
531
532 *idx = 0;
533 list_for_each_entry(pos, &notes->src->source, node) {
534 if (pos->offset == offset)
535 return pos;
29ed6e76 536 if (!disasm_line__filter(&browser->b, &pos->node))
08be4eed
ACM
537 ++*idx;
538 }
539
540 return NULL;
541}
542
543static bool annotate_browser__jump(struct annotate_browser *browser)
544{
657bcaf5 545 struct disasm_line *dl = browser->selection;
4f9d0325 546 s64 idx;
08be4eed 547
75b49202 548 if (!ins__is_jump(&dl->ins))
08be4eed
ACM
549 return false;
550
44d1a3ed 551 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
29ed6e76 552 if (dl == NULL) {
e6f65388 553 ui_helpline__puts("Invalid jump offset");
08be4eed
ACM
554 return true;
555 }
556
29ed6e76 557 annotate_browser__set_top(browser, dl, idx);
48000a1a 558
08be4eed
ACM
559 return true;
560}
561
29ed6e76
ACM
562static
563struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
564 char *s, s64 *idx)
d3d1f61a
ACM
565{
566 struct map_symbol *ms = browser->b.priv;
567 struct symbol *sym = ms->sym;
568 struct annotation *notes = symbol__annotation(sym);
29ed6e76 569 struct disasm_line *pos = browser->selection;
d3d1f61a
ACM
570
571 *idx = browser->b.index;
572 list_for_each_entry_continue(pos, &notes->src->source, node) {
29ed6e76 573 if (disasm_line__filter(&browser->b, &pos->node))
d3d1f61a
ACM
574 continue;
575
576 ++*idx;
577
578 if (pos->line && strstr(pos->line, s) != NULL)
579 return pos;
580 }
581
582 return NULL;
583}
584
585static bool __annotate_browser__search(struct annotate_browser *browser)
586{
29ed6e76 587 struct disasm_line *dl;
d3d1f61a
ACM
588 s64 idx;
589
29ed6e76
ACM
590 dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
591 if (dl == NULL) {
d3d1f61a
ACM
592 ui_helpline__puts("String not found!");
593 return false;
594 }
595
29ed6e76 596 annotate_browser__set_top(browser, dl, idx);
d3d1f61a
ACM
597 browser->searching_backwards = false;
598 return true;
599}
600
29ed6e76
ACM
601static
602struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
603 char *s, s64 *idx)
d3d1f61a
ACM
604{
605 struct map_symbol *ms = browser->b.priv;
606 struct symbol *sym = ms->sym;
607 struct annotation *notes = symbol__annotation(sym);
29ed6e76 608 struct disasm_line *pos = browser->selection;
d3d1f61a
ACM
609
610 *idx = browser->b.index;
611 list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
29ed6e76 612 if (disasm_line__filter(&browser->b, &pos->node))
d3d1f61a
ACM
613 continue;
614
615 --*idx;
616
617 if (pos->line && strstr(pos->line, s) != NULL)
618 return pos;
619 }
620
621 return NULL;
622}
623
624static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
625{
29ed6e76 626 struct disasm_line *dl;
d3d1f61a
ACM
627 s64 idx;
628
29ed6e76
ACM
629 dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
630 if (dl == NULL) {
d3d1f61a
ACM
631 ui_helpline__puts("String not found!");
632 return false;
633 }
634
29ed6e76 635 annotate_browser__set_top(browser, dl, idx);
d3d1f61a
ACM
636 browser->searching_backwards = true;
637 return true;
638}
639
640static bool annotate_browser__search_window(struct annotate_browser *browser,
641 int delay_secs)
642{
643 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
644 "ENTER: OK, ESC: Cancel",
645 delay_secs * 2) != K_ENTER ||
646 !*browser->search_bf)
647 return false;
648
649 return true;
650}
651
652static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
653{
654 if (annotate_browser__search_window(browser, delay_secs))
655 return __annotate_browser__search(browser);
656
657 return false;
658}
659
660static bool annotate_browser__continue_search(struct annotate_browser *browser,
661 int delay_secs)
662{
663 if (!*browser->search_bf)
664 return annotate_browser__search(browser, delay_secs);
665
666 return __annotate_browser__search(browser);
667}
668
669static bool annotate_browser__search_reverse(struct annotate_browser *browser,
670 int delay_secs)
671{
672 if (annotate_browser__search_window(browser, delay_secs))
673 return __annotate_browser__search_reverse(browser);
674
675 return false;
676}
677
678static
679bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
680 int delay_secs)
681{
682 if (!*browser->search_bf)
683 return annotate_browser__search_reverse(browser, delay_secs);
684
685 return __annotate_browser__search_reverse(browser);
686}
687
e9823b21
ACM
688static void annotate_browser__update_addr_width(struct annotate_browser *browser)
689{
690 if (annotate_browser__opts.use_offset)
691 browser->target_width = browser->min_addr_width;
692 else
693 browser->target_width = browser->max_addr_width;
694
695 browser->addr_width = browser->target_width;
696
697 if (annotate_browser__opts.show_nr_jumps)
698 browser->addr_width += browser->jumps_width + 1;
699}
700
db8fd07a
NK
701static int annotate_browser__run(struct annotate_browser *browser,
702 struct perf_evsel *evsel,
9783adf7 703 struct hist_browser_timer *hbt)
c97cf422
ACM
704{
705 struct rb_node *nd = NULL;
05e8b080 706 struct map_symbol *ms = browser->b.priv;
34958544 707 struct symbol *sym = ms->sym;
54e7a4e8 708 const char *help = "Press 'h' for help on key bindings";
9783adf7 709 int delay_secs = hbt ? hbt->refresh : 0;
b50e003d 710 int key;
34f77abc 711 char title[SYM_TITLE_MAX_SIZE];
f1e9214c 712
34f77abc
AH
713 sym_title(sym, ms->map, title, sizeof(title));
714 if (ui_browser__show(&browser->b, title, help) < 0)
f1e9214c 715 return -1;
c97cf422 716
db8fd07a 717 annotate_browser__calc_percent(browser, evsel);
c97cf422 718
05e8b080
ACM
719 if (browser->curr_hot) {
720 annotate_browser__set_rb_top(browser, browser->curr_hot);
721 browser->b.navkeypressed = false;
d3d1f61a 722 }
f1e9214c 723
05e8b080 724 nd = browser->curr_hot;
c97cf422 725
f1e9214c 726 while (1) {
05e8b080 727 key = ui_browser__run(&browser->b, delay_secs);
f1e9214c 728
81cce8de 729 if (delay_secs != 0) {
db8fd07a 730 annotate_browser__calc_percent(browser, evsel);
c97cf422
ACM
731 /*
732 * Current line focus got out of the list of most active
733 * lines, NULL it so that if TAB|UNTAB is pressed, we
734 * move to curr_hot (current hottest line).
735 */
736 if (nd != NULL && RB_EMPTY_NODE(nd))
737 nd = NULL;
738 }
739
b50e003d 740 switch (key) {
cf958003 741 case K_TIMER:
9783adf7
NK
742 if (hbt)
743 hbt->timer(hbt->arg);
81cce8de
ACM
744
745 if (delay_secs != 0)
db8fd07a 746 symbol__annotate_decay_histogram(sym, evsel->idx);
c97cf422 747 continue;
cf958003 748 case K_TAB:
c97cf422
ACM
749 if (nd != NULL) {
750 nd = rb_prev(nd);
751 if (nd == NULL)
05e8b080 752 nd = rb_last(&browser->entries);
c97cf422 753 } else
05e8b080 754 nd = browser->curr_hot;
f1e9214c 755 break;
cf958003 756 case K_UNTAB:
d4913cbd 757 if (nd != NULL) {
c97cf422
ACM
758 nd = rb_next(nd);
759 if (nd == NULL)
05e8b080 760 nd = rb_first(&browser->entries);
d4913cbd 761 } else
05e8b080 762 nd = browser->curr_hot;
c97cf422 763 break;
54e7a4e8 764 case K_F1:
ef7c5372 765 case 'h':
05e8b080 766 ui_browser__help_window(&browser->b,
54e7a4e8
ACM
767 "UP/DOWN/PGUP\n"
768 "PGDN/SPACE Navigate\n"
769 "q/ESC/CTRL+C Exit\n\n"
7727a925
ACM
770 "ENTER Go to target\n"
771 "ESC Exit\n"
107baeca 772 "H Cycle thru hottest instructions\n"
54e7a4e8
ACM
773 "j Toggle showing jump to target arrows\n"
774 "J Toggle showing number of jump sources on targets\n"
775 "n Search next string\n"
776 "o Toggle disassembler output/simplified view\n"
777 "s Toggle source code view\n"
0c4a5bce 778 "t Toggle total period view\n"
54e7a4e8 779 "/ Search string\n"
e592488c 780 "k Toggle line numbers\n"
79ee47fa 781 "r Run available scripts\n"
fcd9fef9 782 "? Search string backwards\n");
54e7a4e8 783 continue;
79ee47fa
FT
784 case 'r':
785 {
786 script_browse(NULL);
787 continue;
788 }
e592488c
AK
789 case 'k':
790 annotate_browser__opts.show_linenr =
791 !annotate_browser__opts.show_linenr;
792 break;
54e7a4e8 793 case 'H':
05e8b080 794 nd = browser->curr_hot;
f1e9214c 795 break;
ef7c5372 796 case 's':
05e8b080 797 if (annotate_browser__toggle_source(browser))
0361fc25
ACM
798 ui_helpline__puts(help);
799 continue;
e235f3f3 800 case 'o':
e9823b21 801 annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
05e8b080 802 annotate_browser__update_addr_width(browser);
e235f3f3 803 continue;
9d1ef56d 804 case 'j':
e9823b21 805 annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
9d1ef56d 806 continue;
2402e4a9 807 case 'J':
e9823b21 808 annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
05e8b080 809 annotate_browser__update_addr_width(browser);
e9823b21 810 continue;
d3d1f61a 811 case '/':
05e8b080 812 if (annotate_browser__search(browser, delay_secs)) {
d3d1f61a
ACM
813show_help:
814 ui_helpline__puts(help);
815 }
816 continue;
817 case 'n':
05e8b080
ACM
818 if (browser->searching_backwards ?
819 annotate_browser__continue_search_reverse(browser, delay_secs) :
820 annotate_browser__continue_search(browser, delay_secs))
d3d1f61a
ACM
821 goto show_help;
822 continue;
823 case '?':
05e8b080 824 if (annotate_browser__search_reverse(browser, delay_secs))
d3d1f61a
ACM
825 goto show_help;
826 continue;
e9823b21
ACM
827 case 'D': {
828 static int seq;
829 ui_helpline__pop();
830 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
05e8b080
ACM
831 seq++, browser->b.nr_entries,
832 browser->b.height,
833 browser->b.index,
834 browser->b.top_idx,
835 browser->nr_asm_entries);
e9823b21
ACM
836 }
837 continue;
cf958003
ACM
838 case K_ENTER:
839 case K_RIGHT:
05e8b080 840 if (browser->selection == NULL)
234a5375 841 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
05e8b080 842 else if (browser->selection->offset == -1)
234a5375 843 ui_helpline__puts("Actions are only available for assembly lines.");
75b49202 844 else if (!browser->selection->ins.ops)
6ef94929 845 goto show_sup_ins;
75b49202 846 else if (ins__is_ret(&browser->selection->ins))
c4cceae3 847 goto out;
6ef94929 848 else if (!(annotate_browser__jump(browser) ||
db8fd07a 849 annotate_browser__callq(browser, evsel, hbt))) {
c4cceae3 850show_sup_ins:
6ef94929 851 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
c4cceae3 852 }
fe46e64c 853 continue;
0c4a5bce
ML
854 case 't':
855 annotate_browser__opts.show_total_period =
856 !annotate_browser__opts.show_total_period;
857 annotate_browser__update_addr_width(browser);
858 continue;
cf958003
ACM
859 case K_LEFT:
860 case K_ESC:
ed7e5662
ACM
861 case 'q':
862 case CTRL('c'):
f1e9214c 863 goto out;
ed7e5662
ACM
864 default:
865 continue;
f1e9214c 866 }
c97cf422
ACM
867
868 if (nd != NULL)
05e8b080 869 annotate_browser__set_rb_top(browser, nd);
f1e9214c
ACM
870 }
871out:
05e8b080 872 ui_browser__hide(&browser->b);
b50e003d 873 return key;
f1e9214c
ACM
874}
875
d5dbc518
ACM
876int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel,
877 struct hist_browser_timer *hbt)
878{
0c4a5bce
ML
879 /* Set default value for show_total_period. */
880 annotate_browser__opts.show_total_period =
881 symbol_conf.show_total_period;
882
d5dbc518
ACM
883 return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt);
884}
885
db8fd07a 886int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
9783adf7 887 struct hist_browser_timer *hbt)
78f7defe 888{
ed426915
NK
889 /* reset abort key so that it can get Ctrl-C as a key */
890 SLang_reset_tty();
891 SLang_init_tty(0, 0, 0);
892
d5dbc518 893 return map_symbol__tui_annotate(&he->ms, evsel, hbt);
78f7defe
ACM
894}
895
30e863bb
AK
896
897static unsigned count_insn(struct annotate_browser *browser, u64 start, u64 end)
898{
899 unsigned n_insn = 0;
900 u64 offset;
901
902 for (offset = start; offset <= end; offset++) {
903 if (browser->offsets[offset])
904 n_insn++;
905 }
906 return n_insn;
907}
908
909static void count_and_fill(struct annotate_browser *browser, u64 start, u64 end,
910 struct cyc_hist *ch)
911{
912 unsigned n_insn;
913 u64 offset;
914
915 n_insn = count_insn(browser, start, end);
916 if (n_insn && ch->num && ch->cycles) {
917 float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
918
919 /* Hide data when there are too many overlaps. */
920 if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
921 return;
922
923 for (offset = start; offset <= end; offset++) {
924 struct disasm_line *dl = browser->offsets[offset];
925
926 if (dl)
927 dl->ipc = ipc;
928 }
929 }
930}
931
932/*
933 * This should probably be in util/annotate.c to share with the tty
934 * annotate, but right now we need the per byte offsets arrays,
935 * which are only here.
936 */
937static void annotate__compute_ipc(struct annotate_browser *browser, size_t size,
938 struct symbol *sym)
939{
940 u64 offset;
941 struct annotation *notes = symbol__annotation(sym);
942
943 if (!notes->src || !notes->src->cycles_hist)
944 return;
945
946 pthread_mutex_lock(&notes->lock);
947 for (offset = 0; offset < size; ++offset) {
948 struct cyc_hist *ch;
949
950 ch = &notes->src->cycles_hist[offset];
951 if (ch && ch->cycles) {
952 struct disasm_line *dl;
953
954 if (ch->have_start)
955 count_and_fill(browser, ch->start, offset, ch);
956 dl = browser->offsets[offset];
957 if (dl && ch->num_aggr)
958 dl->cycles = ch->cycles_aggr / ch->num_aggr;
959 browser->have_cycles = true;
960 }
961 }
962 pthread_mutex_unlock(&notes->lock);
963}
964
b793a401
ACM
965static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
966 size_t size)
967{
968 u64 offset;
32ae1efd
NK
969 struct map_symbol *ms = browser->b.priv;
970 struct symbol *sym = ms->sym;
971
972 /* PLT symbols contain external offsets */
973 if (strstr(sym->name, "@plt"))
974 return;
b793a401
ACM
975
976 for (offset = 0; offset < size; ++offset) {
977 struct disasm_line *dl = browser->offsets[offset], *dlt;
978 struct browser_disasm_line *bdlt;
979
865c66c4 980 if (!disasm_line__is_valid_jump(dl, sym))
b793a401
ACM
981 continue;
982
44d1a3ed 983 dlt = browser->offsets[dl->ops.target.offset];
9481ede9
ACM
984 /*
985 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
986 * have to adjust to the previous offset?
987 */
988 if (dlt == NULL)
989 continue;
990
b793a401 991 bdlt = disasm_line__browser(dlt);
2402e4a9
ACM
992 if (++bdlt->jump_sources > browser->max_jump_sources)
993 browser->max_jump_sources = bdlt->jump_sources;
994
995 ++browser->nr_jumps;
b793a401 996 }
b793a401
ACM
997}
998
2402e4a9
ACM
999static inline int width_jumps(int n)
1000{
1001 if (n >= 100)
1002 return 5;
1003 if (n / 10)
1004 return 2;
1005 return 1;
1006}
1007
db8fd07a
NK
1008int symbol__tui_annotate(struct symbol *sym, struct map *map,
1009 struct perf_evsel *evsel,
9783adf7 1010 struct hist_browser_timer *hbt)
211ef127 1011{
29ed6e76 1012 struct disasm_line *pos, *n;
db9a9cbc 1013 struct annotation *notes;
c0a58fb2 1014 size_t size;
34958544
ACM
1015 struct map_symbol ms = {
1016 .map = map,
1017 .sym = sym,
1018 };
92221162
ACM
1019 struct annotate_browser browser = {
1020 .b = {
a3f895be 1021 .refresh = annotate_browser__refresh,
92221162
ACM
1022 .seek = ui_browser__list_head_seek,
1023 .write = annotate_browser__write,
29ed6e76 1024 .filter = disasm_line__filter,
34958544 1025 .priv = &ms,
c172f742 1026 .use_navkeypressed = true,
92221162 1027 },
211ef127 1028 };
ee51d851 1029 int ret = -1, err;
c7e7b610
NK
1030 int nr_pcnt = 1;
1031 size_t sizeof_bdl = sizeof(struct browser_disasm_line);
211ef127 1032
78f7defe 1033 if (sym == NULL)
211ef127
ACM
1034 return -1;
1035
c0a58fb2
SL
1036 size = symbol__size(sym);
1037
78f7defe 1038 if (map->dso->annotate_warned)
211ef127
ACM
1039 return -1;
1040
b793a401
ACM
1041 browser.offsets = zalloc(size * sizeof(struct disasm_line *));
1042 if (browser.offsets == NULL) {
1043 ui__error("Not enough memory!");
1044 return -1;
1045 }
1046
c7e7b610
NK
1047 if (perf_evsel__is_group_event(evsel)) {
1048 nr_pcnt = evsel->nr_members;
0c4a5bce
ML
1049 sizeof_bdl += sizeof(struct disasm_line_samples) *
1050 (nr_pcnt - 1);
c7e7b610
NK
1051 }
1052
786c1b51 1053 err = symbol__disassemble(sym, map, perf_evsel__env_arch(evsel), sizeof_bdl);
ee51d851
ACM
1054 if (err) {
1055 char msg[BUFSIZ];
1056 symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg));
1057 ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
b793a401 1058 goto out_free_offsets;
211ef127
ACM
1059 }
1060
7727a925 1061 ui_helpline__push("Press ESC to exit");
211ef127 1062
db9a9cbc 1063 notes = symbol__annotation(sym);
058b4cc9 1064 browser.start = map__rip_2objdump(map, sym->start);
db9a9cbc 1065
ce6f4fab 1066 list_for_each_entry(pos, &notes->src->source, node) {
887c0066 1067 struct browser_disasm_line *bpos;
211ef127 1068 size_t line_len = strlen(pos->line);
c97cf422 1069
92221162
ACM
1070 if (browser.b.width < line_len)
1071 browser.b.width = line_len;
887c0066
ACM
1072 bpos = disasm_line__browser(pos);
1073 bpos->idx = browser.nr_entries++;
b793a401 1074 if (pos->offset != -1) {
887c0066 1075 bpos->idx_asm = browser.nr_asm_entries++;
97148a97
ACM
1076 /*
1077 * FIXME: short term bandaid to cope with assembly
1078 * routines that comes with labels in the same column
1079 * as the address in objdump, sigh.
1080 *
1081 * E.g. copy_user_generic_unrolled
1082 */
1083 if (pos->offset < (s64)size)
1084 browser.offsets[pos->offset] = pos;
b793a401 1085 } else
887c0066 1086 bpos->idx_asm = -1;
92221162
ACM
1087 }
1088
b793a401 1089 annotate_browser__mark_jump_targets(&browser, size);
30e863bb 1090 annotate__compute_ipc(&browser, size, sym);
b793a401 1091
2402e4a9 1092 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
83b1f2aa 1093 browser.max_addr_width = hex_width(sym->end);
2402e4a9 1094 browser.jumps_width = width_jumps(browser.max_jump_sources);
c7e7b610 1095 browser.nr_events = nr_pcnt;
0361fc25 1096 browser.b.nr_entries = browser.nr_entries;
db9a9cbc 1097 browser.b.entries = &notes->src->source,
92221162 1098 browser.b.width += 18; /* Percentage */
e9823b21
ACM
1099
1100 if (annotate_browser__opts.hide_src_code)
1101 annotate_browser__init_asm_mode(&browser);
1102
1103 annotate_browser__update_addr_width(&browser);
1104
db8fd07a 1105 ret = annotate_browser__run(&browser, evsel, hbt);
ce6f4fab 1106 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
211ef127 1107 list_del(&pos->node);
29ed6e76 1108 disasm_line__free(pos);
211ef127 1109 }
b793a401
ACM
1110
1111out_free_offsets:
1112 free(browser.offsets);
211ef127
ACM
1113 return ret;
1114}
c323cf04
ACM
1115
1116#define ANNOTATE_CFG(n) \
1117 { .name = #n, .value = &annotate_browser__opts.n, }
865c66c4 1118
c323cf04
ACM
1119/*
1120 * Keep the entries sorted, they are bsearch'ed
1121 */
7c3102b8 1122static struct annotate_config {
c323cf04
ACM
1123 const char *name;
1124 bool *value;
1125} annotate__configs[] = {
1126 ANNOTATE_CFG(hide_src_code),
1127 ANNOTATE_CFG(jump_arrows),
e592488c 1128 ANNOTATE_CFG(show_linenr),
c323cf04 1129 ANNOTATE_CFG(show_nr_jumps),
0c4a5bce 1130 ANNOTATE_CFG(show_total_period),
39ff7cdb 1131 ANNOTATE_CFG(use_offset),
c323cf04
ACM
1132};
1133
1134#undef ANNOTATE_CFG
1135
1136static int annotate_config__cmp(const void *name, const void *cfgp)
1137{
7c3102b8 1138 const struct annotate_config *cfg = cfgp;
c323cf04
ACM
1139
1140 return strcmp(name, cfg->name);
1141}
1142
1d037ca1
IT
1143static int annotate__config(const char *var, const char *value,
1144 void *data __maybe_unused)
c323cf04 1145{
7c3102b8 1146 struct annotate_config *cfg;
c323cf04
ACM
1147 const char *name;
1148
1149 if (prefixcmp(var, "annotate.") != 0)
1150 return 0;
1151
1152 name = var + 9;
1153 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
7c3102b8 1154 sizeof(struct annotate_config), annotate_config__cmp);
c323cf04
ACM
1155
1156 if (cfg == NULL)
f06cff7c
ACM
1157 ui__warning("%s variable unknown, ignoring...", var);
1158 else
1159 *cfg->value = perf_config_bool(name, value);
c323cf04
ACM
1160 return 0;
1161}
1162
1163void annotate_browser__init(void)
1164{
1165 perf_config(annotate__config, NULL);
1166}