perf annotate browser: The idx_asm field should be used in asm only view
[deliverable/linux.git] / tools / perf / ui / browsers / annotate.c
CommitLineData
aca7a94d 1#include "../../util/util.h"
211ef127
ACM
2#include "../browser.h"
3#include "../helpline.h"
4#include "../libslang.h"
ae55795e
ACM
5#include "../ui.h"
6#include "../util.h"
aca7a94d
NK
7#include "../../util/annotate.h"
8#include "../../util/hist.h"
9#include "../../util/sort.h"
10#include "../../util/symbol.h"
c97cf422 11#include <pthread.h>
cf958003 12#include <newt.h>
211ef127 13
b793a401
ACM
14struct browser_disasm_line {
15 struct rb_node rb_node;
16 double percent;
17 u32 idx;
18 int idx_asm;
7d5b12f5 19 int jump_sources;
b793a401
ACM
20};
21
92221162
ACM
22struct annotate_browser {
23 struct ui_browser b;
24 struct rb_root entries;
f1e9214c 25 struct rb_node *curr_hot;
29ed6e76 26 struct disasm_line *selection;
b793a401 27 struct disasm_line **offsets;
058b4cc9 28 u64 start;
0361fc25
ACM
29 int nr_asm_entries;
30 int nr_entries;
2402e4a9
ACM
31 int max_jump_sources;
32 int nr_jumps;
0361fc25 33 bool hide_src_code;
e235f3f3 34 bool use_offset;
9d1ef56d 35 bool jump_arrows;
2402e4a9 36 bool show_nr_jumps;
d3d1f61a 37 bool searching_backwards;
83b1f2aa 38 u8 addr_width;
2402e4a9
ACM
39 u8 jumps_width;
40 u8 target_width;
83b1f2aa
ACM
41 u8 min_addr_width;
42 u8 max_addr_width;
d3d1f61a 43 char search_bf[128];
92221162
ACM
44};
45
887c0066 46static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
92221162 47{
887c0066 48 return (struct browser_disasm_line *)(dl + 1);
92221162
ACM
49}
50
29ed6e76 51static bool disasm_line__filter(struct ui_browser *browser, void *entry)
0361fc25
ACM
52{
53 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
54
55 if (ab->hide_src_code) {
29ed6e76
ACM
56 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
57 return dl->offset == -1;
0361fc25
ACM
58 }
59
60 return false;
61}
62
2402e4a9
ACM
63static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
64 int nr, bool current)
65{
66 if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
67 return HE_COLORSET_SELECTED;
68 if (nr == browser->max_jump_sources)
69 return HE_COLORSET_TOP;
70 if (nr > 1)
71 return HE_COLORSET_MEDIUM;
72 return HE_COLORSET_NORMAL;
73}
74
75static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
76 int nr, bool current)
77{
78 int color = annotate_browser__jumps_percent_color(browser, nr, current);
79 return ui_browser__set_color(&browser->b, color);
80}
81
211ef127
ACM
82static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
83{
34958544 84 struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
29ed6e76 85 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
b793a401 86 struct browser_disasm_line *bdl = disasm_line__browser(dl);
211ef127 87 bool current_entry = ui_browser__is_current_entry(self, row);
058b4cc9
ACM
88 bool change_color = (!ab->hide_src_code &&
89 (!current_entry || (self->use_navkeypressed &&
90 !self->navkeypressed)));
83b1f2aa
ACM
91 int width = self->width, printed;
92 char bf[256];
211ef127 93
0822cc80 94 if (dl->offset != -1 && bdl->percent != 0.0) {
887c0066 95 ui_browser__set_percent_color(self, bdl->percent, current_entry);
0822cc80 96 slsmg_printf("%6.2f ", bdl->percent);
92221162 97 } else {
8f9bbc40 98 ui_browser__set_percent_color(self, 0, current_entry);
0822cc80 99 slsmg_write_nstring(" ", 7);
92221162
ACM
100 }
101
cf2dacc5 102 SLsmg_write_char(' ');
c172f742
ACM
103
104 /* The scroll bar isn't being used */
105 if (!self->navkeypressed)
106 width += 1;
107
29ed6e76 108 if (!*dl->line)
0822cc80 109 slsmg_write_nstring(" ", width - 7);
83b1f2aa
ACM
110 else if (dl->offset == -1) {
111 printed = scnprintf(bf, sizeof(bf), "%*s ",
112 ab->addr_width, " ");
113 slsmg_write_nstring(bf, printed);
114 slsmg_write_nstring(dl->line, width - printed - 6);
115 } else {
29ed6e76 116 u64 addr = dl->offset;
83b1f2aa 117 int color = -1;
058b4cc9 118
e235f3f3
ACM
119 if (!ab->use_offset)
120 addr += ab->start;
121
61e04b33 122 if (!ab->use_offset) {
83b1f2aa 123 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
61e04b33 124 } else {
7d5b12f5 125 if (bdl->jump_sources) {
2402e4a9
ACM
126 if (ab->show_nr_jumps) {
127 int prev;
128 printed = scnprintf(bf, sizeof(bf), "%*d ",
129 ab->jumps_width,
130 bdl->jump_sources);
131 prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
132 current_entry);
133 slsmg_write_nstring(bf, printed);
134 ui_browser__set_color(self, prev);
135 }
136
83b1f2aa 137 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
2402e4a9 138 ab->target_width, addr);
61e04b33 139 } else {
83b1f2aa
ACM
140 printed = scnprintf(bf, sizeof(bf), "%*s ",
141 ab->addr_width, " ");
61e04b33
ACM
142 }
143 }
b793a401 144
058b4cc9
ACM
145 if (change_color)
146 color = ui_browser__set_color(self, HE_COLORSET_ADDR);
147 slsmg_write_nstring(bf, printed);
148 if (change_color)
149 ui_browser__set_color(self, color);
28548d78 150 if (dl->ins && dl->ins->ops->scnprintf) {
51a0d455 151 if (ins__is_jump(dl->ins)) {
44d1a3ed 152 bool fwd = dl->ops.target.offset > (u64)dl->offset;
51a0d455 153
59d038d5
ACM
154 ui_browser__write_graph(self, fwd ? SLSMG_DARROW_CHAR :
155 SLSMG_UARROW_CHAR);
51a0d455 156 SLsmg_write_char(' ');
88298f5a
ACM
157 } else if (ins__is_call(dl->ins)) {
158 ui_browser__write_graph(self, SLSMG_RARROW_CHAR);
159 SLsmg_write_char(' ');
51a0d455
ACM
160 } else {
161 slsmg_write_nstring(" ", 2);
162 }
4ea08b52
ACM
163 } else {
164 if (strcmp(dl->name, "retq")) {
165 slsmg_write_nstring(" ", 2);
166 } else {
59d038d5 167 ui_browser__write_graph(self, SLSMG_LARROW_CHAR);
4ea08b52
ACM
168 SLsmg_write_char(' ');
169 }
4ea08b52 170 }
28548d78 171
5417072b 172 disasm_line__scnprintf(dl, bf, sizeof(bf), !ab->use_offset);
83b1f2aa 173 slsmg_write_nstring(bf, width - 10 - printed);
058b4cc9 174 }
b99976e2 175
58e817d9 176 if (current_entry)
29ed6e76 177 ab->selection = dl;
92221162
ACM
178}
179
9d1ef56d 180static void annotate_browser__draw_current_jump(struct ui_browser *browser)
a3f895be
ACM
181{
182 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
9d1ef56d
ACM
183 struct disasm_line *cursor = ab->selection, *target;
184 struct browser_disasm_line *btarget, *bcursor;
83b1f2aa 185 unsigned int from, to;
a3f895be 186
9d1ef56d
ACM
187 if (!cursor->ins || !ins__is_jump(cursor->ins) ||
188 !disasm_line__has_offset(cursor))
189 return;
a3f895be 190
9d1ef56d
ACM
191 target = ab->offsets[cursor->ops.target.offset];
192 if (!target)
193 return;
a3f895be 194
9d1ef56d
ACM
195 bcursor = disasm_line__browser(cursor);
196 btarget = disasm_line__browser(target);
a3f895be 197
a3f895be 198 if (ab->hide_src_code) {
9d1ef56d 199 from = bcursor->idx_asm;
a3f895be
ACM
200 to = btarget->idx_asm;
201 } else {
9d1ef56d 202 from = (u64)bcursor->idx;
a3f895be
ACM
203 to = (u64)btarget->idx;
204 }
205
206 ui_browser__set_color(browser, HE_COLORSET_CODE);
83b1f2aa 207 __ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to);
a3f895be
ACM
208}
209
210static unsigned int annotate_browser__refresh(struct ui_browser *browser)
211{
9d1ef56d 212 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
a3f895be
ACM
213 int ret = ui_browser__list_head_refresh(browser);
214
9d1ef56d
ACM
215 if (ab->jump_arrows)
216 annotate_browser__draw_current_jump(browser);
a3f895be 217
83b1f2aa
ACM
218 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
219 __ui_browser__vline(browser, 7, 0, browser->height - 1);
a3f895be
ACM
220 return ret;
221}
222
29ed6e76 223static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx)
92221162
ACM
224{
225 double percent = 0.0;
226
29ed6e76 227 if (dl->offset != -1) {
92221162 228 int len = sym->end - sym->start;
211ef127 229 unsigned int hits = 0;
78f7defe 230 struct annotation *notes = symbol__annotation(sym);
ce6f4fab 231 struct source_line *src_line = notes->src->lines;
2f525d01 232 struct sym_hist *h = annotation__histogram(notes, evidx);
29ed6e76
ACM
233 s64 offset = dl->offset;
234 struct disasm_line *next;
92221162 235
29ed6e76 236 next = disasm__get_next_ip_line(&notes->src->source, dl);
211ef127
ACM
237 while (offset < (s64)len &&
238 (next == NULL || offset < next->offset)) {
78f7defe
ACM
239 if (src_line) {
240 percent += src_line[offset].percent;
211ef127 241 } else
78f7defe 242 hits += h->addr[offset];
211ef127
ACM
243
244 ++offset;
245 }
78f7defe
ACM
246 /*
247 * If the percentage wasn't already calculated in
248 * symbol__get_source_line, do it now:
249 */
250 if (src_line == NULL && h->sum)
211ef127 251 percent = 100.0 * hits / h->sum;
211ef127
ACM
252 }
253
92221162
ACM
254 return percent;
255}
256
887c0066 257static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl)
92221162 258{
29ed6e76 259 struct rb_node **p = &root->rb_node;
92221162 260 struct rb_node *parent = NULL;
887c0066 261 struct browser_disasm_line *l;
92221162
ACM
262
263 while (*p != NULL) {
264 parent = *p;
887c0066
ACM
265 l = rb_entry(parent, struct browser_disasm_line, rb_node);
266 if (bdl->percent < l->percent)
92221162
ACM
267 p = &(*p)->rb_left;
268 else
269 p = &(*p)->rb_right;
270 }
887c0066
ACM
271 rb_link_node(&bdl->rb_node, parent, p);
272 rb_insert_color(&bdl->rb_node, root);
211ef127
ACM
273}
274
f1e9214c 275static void annotate_browser__set_top(struct annotate_browser *self,
29ed6e76 276 struct disasm_line *pos, u32 idx)
f1e9214c 277{
f1e9214c
ACM
278 unsigned back;
279
280 ui_browser__refresh_dimensions(&self->b);
281 back = self->b.height / 2;
b0ffb2c4 282 self->b.top_idx = self->b.index = idx;
f1e9214c
ACM
283
284 while (self->b.top_idx != 0 && back != 0) {
29ed6e76 285 pos = list_entry(pos->node.prev, struct disasm_line, node);
f1e9214c 286
29ed6e76 287 if (disasm_line__filter(&self->b, &pos->node))
08be4eed
ACM
288 continue;
289
f1e9214c
ACM
290 --self->b.top_idx;
291 --back;
292 }
293
294 self->b.top = pos;
d3d1f61a 295 self->b.navkeypressed = true;
b0ffb2c4
ACM
296}
297
298static void annotate_browser__set_rb_top(struct annotate_browser *browser,
299 struct rb_node *nd)
300{
887c0066 301 struct browser_disasm_line *bpos;
29ed6e76 302 struct disasm_line *pos;
a44b45f2 303 u32 idx;
b0ffb2c4 304
887c0066
ACM
305 bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
306 pos = ((struct disasm_line *)bpos) - 1;
a44b45f2
ACM
307 idx = bpos->idx;
308 if (browser->hide_src_code)
309 idx = bpos->idx_asm;
310 annotate_browser__set_top(browser, pos, idx);
b0ffb2c4 311 browser->curr_hot = nd;
f1e9214c
ACM
312}
313
c97cf422
ACM
314static void annotate_browser__calc_percent(struct annotate_browser *browser,
315 int evidx)
f1e9214c 316{
34958544
ACM
317 struct map_symbol *ms = browser->b.priv;
318 struct symbol *sym = ms->sym;
c97cf422 319 struct annotation *notes = symbol__annotation(sym);
29ed6e76 320 struct disasm_line *pos;
c97cf422
ACM
321
322 browser->entries = RB_ROOT;
323
324 pthread_mutex_lock(&notes->lock);
325
326 list_for_each_entry(pos, &notes->src->source, node) {
887c0066
ACM
327 struct browser_disasm_line *bpos = disasm_line__browser(pos);
328 bpos->percent = disasm_line__calc_percent(pos, sym, evidx);
329 if (bpos->percent < 0.01) {
330 RB_CLEAR_NODE(&bpos->rb_node);
c97cf422
ACM
331 continue;
332 }
887c0066 333 disasm_rb_tree__insert(&browser->entries, bpos);
c97cf422
ACM
334 }
335 pthread_mutex_unlock(&notes->lock);
336
337 browser->curr_hot = rb_last(&browser->entries);
338}
339
0361fc25
ACM
340static bool annotate_browser__toggle_source(struct annotate_browser *browser)
341{
29ed6e76 342 struct disasm_line *dl;
887c0066 343 struct browser_disasm_line *bdl;
0361fc25
ACM
344 off_t offset = browser->b.index - browser->b.top_idx;
345
346 browser->b.seek(&browser->b, offset, SEEK_CUR);
29ed6e76 347 dl = list_entry(browser->b.top, struct disasm_line, node);
887c0066 348 bdl = disasm_line__browser(dl);
0361fc25
ACM
349
350 if (browser->hide_src_code) {
887c0066
ACM
351 if (bdl->idx_asm < offset)
352 offset = bdl->idx;
0361fc25
ACM
353
354 browser->b.nr_entries = browser->nr_entries;
355 browser->hide_src_code = false;
356 browser->b.seek(&browser->b, -offset, SEEK_CUR);
887c0066
ACM
357 browser->b.top_idx = bdl->idx - offset;
358 browser->b.index = bdl->idx;
0361fc25 359 } else {
887c0066 360 if (bdl->idx_asm < 0) {
0361fc25
ACM
361 ui_helpline__puts("Only available for assembly lines.");
362 browser->b.seek(&browser->b, -offset, SEEK_CUR);
363 return false;
364 }
365
887c0066
ACM
366 if (bdl->idx_asm < offset)
367 offset = bdl->idx_asm;
0361fc25
ACM
368
369 browser->b.nr_entries = browser->nr_asm_entries;
370 browser->hide_src_code = true;
371 browser->b.seek(&browser->b, -offset, SEEK_CUR);
887c0066
ACM
372 browser->b.top_idx = bdl->idx_asm - offset;
373 browser->b.index = bdl->idx_asm;
0361fc25
ACM
374 }
375
376 return true;
377}
378
60521702
ACM
379static bool annotate_browser__callq(struct annotate_browser *browser,
380 int evidx, void (*timer)(void *arg),
381 void *arg, int delay_secs)
382{
383 struct map_symbol *ms = browser->b.priv;
657bcaf5 384 struct disasm_line *dl = browser->selection;
60521702
ACM
385 struct symbol *sym = ms->sym;
386 struct annotation *notes;
387 struct symbol *target;
60521702
ACM
388 u64 ip;
389
d86b0597 390 if (!ins__is_call(dl->ins))
60521702
ACM
391 return false;
392
44d1a3ed 393 ip = ms->map->map_ip(ms->map, dl->ops.target.addr);
60521702
ACM
394 target = map__find_symbol(ms->map, ip, NULL);
395 if (target == NULL) {
396 ui_helpline__puts("The called function was not found.");
397 return true;
398 }
399
400 notes = symbol__annotation(target);
401 pthread_mutex_lock(&notes->lock);
402
403 if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
404 pthread_mutex_unlock(&notes->lock);
405 ui__warning("Not enough memory for annotating '%s' symbol!\n",
406 target->name);
407 return true;
408 }
409
410 pthread_mutex_unlock(&notes->lock);
411 symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs);
412 ui_browser__show_title(&browser->b, sym->name);
413 return true;
414}
415
29ed6e76
ACM
416static
417struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
418 s64 offset, s64 *idx)
08be4eed
ACM
419{
420 struct map_symbol *ms = browser->b.priv;
421 struct symbol *sym = ms->sym;
422 struct annotation *notes = symbol__annotation(sym);
29ed6e76 423 struct disasm_line *pos;
08be4eed
ACM
424
425 *idx = 0;
426 list_for_each_entry(pos, &notes->src->source, node) {
427 if (pos->offset == offset)
428 return pos;
29ed6e76 429 if (!disasm_line__filter(&browser->b, &pos->node))
08be4eed
ACM
430 ++*idx;
431 }
432
433 return NULL;
434}
435
436static bool annotate_browser__jump(struct annotate_browser *browser)
437{
657bcaf5 438 struct disasm_line *dl = browser->selection;
4f9d0325 439 s64 idx;
08be4eed 440
d86b0597 441 if (!ins__is_jump(dl->ins))
08be4eed
ACM
442 return false;
443
44d1a3ed 444 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
29ed6e76 445 if (dl == NULL) {
08be4eed
ACM
446 ui_helpline__puts("Invallid jump offset");
447 return true;
448 }
449
29ed6e76 450 annotate_browser__set_top(browser, dl, idx);
08be4eed
ACM
451
452 return true;
453}
454
29ed6e76
ACM
455static
456struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
457 char *s, s64 *idx)
d3d1f61a
ACM
458{
459 struct map_symbol *ms = browser->b.priv;
460 struct symbol *sym = ms->sym;
461 struct annotation *notes = symbol__annotation(sym);
29ed6e76 462 struct disasm_line *pos = browser->selection;
d3d1f61a
ACM
463
464 *idx = browser->b.index;
465 list_for_each_entry_continue(pos, &notes->src->source, node) {
29ed6e76 466 if (disasm_line__filter(&browser->b, &pos->node))
d3d1f61a
ACM
467 continue;
468
469 ++*idx;
470
471 if (pos->line && strstr(pos->line, s) != NULL)
472 return pos;
473 }
474
475 return NULL;
476}
477
478static bool __annotate_browser__search(struct annotate_browser *browser)
479{
29ed6e76 480 struct disasm_line *dl;
d3d1f61a
ACM
481 s64 idx;
482
29ed6e76
ACM
483 dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
484 if (dl == NULL) {
d3d1f61a
ACM
485 ui_helpline__puts("String not found!");
486 return false;
487 }
488
29ed6e76 489 annotate_browser__set_top(browser, dl, idx);
d3d1f61a
ACM
490 browser->searching_backwards = false;
491 return true;
492}
493
29ed6e76
ACM
494static
495struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
496 char *s, s64 *idx)
d3d1f61a
ACM
497{
498 struct map_symbol *ms = browser->b.priv;
499 struct symbol *sym = ms->sym;
500 struct annotation *notes = symbol__annotation(sym);
29ed6e76 501 struct disasm_line *pos = browser->selection;
d3d1f61a
ACM
502
503 *idx = browser->b.index;
504 list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
29ed6e76 505 if (disasm_line__filter(&browser->b, &pos->node))
d3d1f61a
ACM
506 continue;
507
508 --*idx;
509
510 if (pos->line && strstr(pos->line, s) != NULL)
511 return pos;
512 }
513
514 return NULL;
515}
516
517static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
518{
29ed6e76 519 struct disasm_line *dl;
d3d1f61a
ACM
520 s64 idx;
521
29ed6e76
ACM
522 dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
523 if (dl == NULL) {
d3d1f61a
ACM
524 ui_helpline__puts("String not found!");
525 return false;
526 }
527
29ed6e76 528 annotate_browser__set_top(browser, dl, idx);
d3d1f61a
ACM
529 browser->searching_backwards = true;
530 return true;
531}
532
533static bool annotate_browser__search_window(struct annotate_browser *browser,
534 int delay_secs)
535{
536 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
537 "ENTER: OK, ESC: Cancel",
538 delay_secs * 2) != K_ENTER ||
539 !*browser->search_bf)
540 return false;
541
542 return true;
543}
544
545static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
546{
547 if (annotate_browser__search_window(browser, delay_secs))
548 return __annotate_browser__search(browser);
549
550 return false;
551}
552
553static bool annotate_browser__continue_search(struct annotate_browser *browser,
554 int delay_secs)
555{
556 if (!*browser->search_bf)
557 return annotate_browser__search(browser, delay_secs);
558
559 return __annotate_browser__search(browser);
560}
561
562static bool annotate_browser__search_reverse(struct annotate_browser *browser,
563 int delay_secs)
564{
565 if (annotate_browser__search_window(browser, delay_secs))
566 return __annotate_browser__search_reverse(browser);
567
568 return false;
569}
570
571static
572bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
573 int delay_secs)
574{
575 if (!*browser->search_bf)
576 return annotate_browser__search_reverse(browser, delay_secs);
577
578 return __annotate_browser__search_reverse(browser);
579}
580
c97cf422 581static int annotate_browser__run(struct annotate_browser *self, int evidx,
d04b35f8 582 void(*timer)(void *arg),
34958544 583 void *arg, int delay_secs)
c97cf422
ACM
584{
585 struct rb_node *nd = NULL;
34958544
ACM
586 struct map_symbol *ms = self->b.priv;
587 struct symbol *sym = ms->sym;
54e7a4e8 588 const char *help = "Press 'h' for help on key bindings";
b50e003d 589 int key;
f1e9214c 590
0361fc25 591 if (ui_browser__show(&self->b, sym->name, help) < 0)
f1e9214c 592 return -1;
c97cf422 593
c97cf422
ACM
594 annotate_browser__calc_percent(self, evidx);
595
d3d1f61a 596 if (self->curr_hot) {
b0ffb2c4 597 annotate_browser__set_rb_top(self, self->curr_hot);
d3d1f61a
ACM
598 self->b.navkeypressed = false;
599 }
f1e9214c
ACM
600
601 nd = self->curr_hot;
c97cf422 602
f1e9214c 603 while (1) {
3af6e338 604 key = ui_browser__run(&self->b, delay_secs);
f1e9214c 605
81cce8de 606 if (delay_secs != 0) {
c97cf422
ACM
607 annotate_browser__calc_percent(self, evidx);
608 /*
609 * Current line focus got out of the list of most active
610 * lines, NULL it so that if TAB|UNTAB is pressed, we
611 * move to curr_hot (current hottest line).
612 */
613 if (nd != NULL && RB_EMPTY_NODE(nd))
614 nd = NULL;
615 }
616
b50e003d 617 switch (key) {
cf958003 618 case K_TIMER:
81cce8de
ACM
619 if (timer != NULL)
620 timer(arg);
621
622 if (delay_secs != 0)
c97cf422
ACM
623 symbol__annotate_decay_histogram(sym, evidx);
624 continue;
cf958003 625 case K_TAB:
c97cf422
ACM
626 if (nd != NULL) {
627 nd = rb_prev(nd);
628 if (nd == NULL)
629 nd = rb_last(&self->entries);
630 } else
631 nd = self->curr_hot;
f1e9214c 632 break;
cf958003 633 case K_UNTAB:
c97cf422
ACM
634 if (nd != NULL)
635 nd = rb_next(nd);
636 if (nd == NULL)
637 nd = rb_first(&self->entries);
638 else
639 nd = self->curr_hot;
640 break;
54e7a4e8 641 case K_F1:
ef7c5372 642 case 'h':
54e7a4e8
ACM
643 ui_browser__help_window(&self->b,
644 "UP/DOWN/PGUP\n"
645 "PGDN/SPACE Navigate\n"
646 "q/ESC/CTRL+C Exit\n\n"
647 "-> Go to target\n"
648 "<- Exit\n"
649 "h Cycle thru hottest instructions\n"
650 "j Toggle showing jump to target arrows\n"
651 "J Toggle showing number of jump sources on targets\n"
652 "n Search next string\n"
653 "o Toggle disassembler output/simplified view\n"
654 "s Toggle source code view\n"
655 "/ Search string\n"
656 "? Search previous string\n");
657 continue;
658 case 'H':
c97cf422 659 nd = self->curr_hot;
f1e9214c 660 break;
ef7c5372 661 case 's':
0361fc25
ACM
662 if (annotate_browser__toggle_source(self))
663 ui_helpline__puts(help);
664 continue;
e235f3f3
ACM
665 case 'o':
666 self->use_offset = !self->use_offset;
83b1f2aa 667 if (self->use_offset)
2402e4a9 668 self->target_width = self->min_addr_width;
83b1f2aa 669 else
2402e4a9
ACM
670 self->target_width = self->max_addr_width;
671update_addr_width:
672 self->addr_width = self->target_width;
673 if (self->show_nr_jumps)
674 self->addr_width += self->jumps_width + 1;
e235f3f3 675 continue;
9d1ef56d
ACM
676 case 'j':
677 self->jump_arrows = !self->jump_arrows;
678 continue;
2402e4a9
ACM
679 case 'J':
680 self->show_nr_jumps = !self->show_nr_jumps;
681 goto update_addr_width;
d3d1f61a
ACM
682 case '/':
683 if (annotate_browser__search(self, delay_secs)) {
684show_help:
685 ui_helpline__puts(help);
686 }
687 continue;
688 case 'n':
689 if (self->searching_backwards ?
690 annotate_browser__continue_search_reverse(self, delay_secs) :
691 annotate_browser__continue_search(self, delay_secs))
692 goto show_help;
693 continue;
694 case '?':
695 if (annotate_browser__search_reverse(self, delay_secs))
696 goto show_help;
697 continue;
cf958003
ACM
698 case K_ENTER:
699 case K_RIGHT:
60521702 700 if (self->selection == NULL)
234a5375 701 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
60521702 702 else if (self->selection->offset == -1)
234a5375 703 ui_helpline__puts("Actions are only available for assembly lines.");
c4cceae3
ACM
704 else if (!self->selection->ins) {
705 if (strcmp(self->selection->name, "retq"))
706 goto show_sup_ins;
707 goto out;
708 } else if (!(annotate_browser__jump(self) ||
709 annotate_browser__callq(self, evidx, timer, arg, delay_secs))) {
710show_sup_ins:
711 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
712 }
fe46e64c 713 continue;
cf958003
ACM
714 case K_LEFT:
715 case K_ESC:
ed7e5662
ACM
716 case 'q':
717 case CTRL('c'):
f1e9214c 718 goto out;
ed7e5662
ACM
719 default:
720 continue;
f1e9214c 721 }
c97cf422
ACM
722
723 if (nd != NULL)
b0ffb2c4 724 annotate_browser__set_rb_top(self, nd);
f1e9214c
ACM
725 }
726out:
59e8fe32 727 ui_browser__hide(&self->b);
b50e003d 728 return key;
f1e9214c
ACM
729}
730
d04b35f8 731int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
81cce8de 732 void(*timer)(void *arg), void *arg, int delay_secs)
78f7defe 733{
d04b35f8 734 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
81cce8de 735 timer, arg, delay_secs);
78f7defe
ACM
736}
737
b793a401
ACM
738static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
739 size_t size)
740{
741 u64 offset;
742
743 for (offset = 0; offset < size; ++offset) {
744 struct disasm_line *dl = browser->offsets[offset], *dlt;
745 struct browser_disasm_line *bdlt;
746
38b31bd0
ACM
747 if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
748 !disasm_line__has_offset(dl))
b793a401
ACM
749 continue;
750
44d1a3ed 751 if (dl->ops.target.offset >= size) {
b793a401
ACM
752 ui__error("jump to after symbol!\n"
753 "size: %zx, jump target: %" PRIx64,
44d1a3ed 754 size, dl->ops.target.offset);
b793a401
ACM
755 continue;
756 }
757
44d1a3ed 758 dlt = browser->offsets[dl->ops.target.offset];
9481ede9
ACM
759 /*
760 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
761 * have to adjust to the previous offset?
762 */
763 if (dlt == NULL)
764 continue;
765
b793a401 766 bdlt = disasm_line__browser(dlt);
2402e4a9
ACM
767 if (++bdlt->jump_sources > browser->max_jump_sources)
768 browser->max_jump_sources = bdlt->jump_sources;
769
770 ++browser->nr_jumps;
b793a401
ACM
771 }
772
773}
774
2402e4a9
ACM
775static inline int width_jumps(int n)
776{
777 if (n >= 100)
778 return 5;
779 if (n / 10)
780 return 2;
781 return 1;
782}
783
c97cf422 784int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
d04b35f8 785 void(*timer)(void *arg), void *arg,
34958544 786 int delay_secs)
211ef127 787{
29ed6e76 788 struct disasm_line *pos, *n;
db9a9cbc 789 struct annotation *notes;
b793a401 790 const size_t size = symbol__size(sym);
34958544
ACM
791 struct map_symbol ms = {
792 .map = map,
793 .sym = sym,
794 };
92221162
ACM
795 struct annotate_browser browser = {
796 .b = {
a3f895be 797 .refresh = annotate_browser__refresh,
92221162
ACM
798 .seek = ui_browser__list_head_seek,
799 .write = annotate_browser__write,
29ed6e76 800 .filter = disasm_line__filter,
34958544 801 .priv = &ms,
c172f742 802 .use_navkeypressed = true,
92221162 803 },
8bf39cb8 804 .use_offset = true,
9d1ef56d 805 .jump_arrows = true,
211ef127 806 };
b793a401 807 int ret = -1;
211ef127 808
78f7defe 809 if (sym == NULL)
211ef127
ACM
810 return -1;
811
78f7defe 812 if (map->dso->annotate_warned)
211ef127
ACM
813 return -1;
814
b793a401
ACM
815 browser.offsets = zalloc(size * sizeof(struct disasm_line *));
816 if (browser.offsets == NULL) {
817 ui__error("Not enough memory!");
818 return -1;
819 }
820
887c0066 821 if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
ae55795e 822 ui__error("%s", ui_helpline__last_msg);
b793a401 823 goto out_free_offsets;
211ef127
ACM
824 }
825
826 ui_helpline__push("Press <- or ESC to exit");
827
db9a9cbc 828 notes = symbol__annotation(sym);
058b4cc9 829 browser.start = map__rip_2objdump(map, sym->start);
db9a9cbc 830
ce6f4fab 831 list_for_each_entry(pos, &notes->src->source, node) {
887c0066 832 struct browser_disasm_line *bpos;
211ef127 833 size_t line_len = strlen(pos->line);
c97cf422 834
92221162
ACM
835 if (browser.b.width < line_len)
836 browser.b.width = line_len;
887c0066
ACM
837 bpos = disasm_line__browser(pos);
838 bpos->idx = browser.nr_entries++;
b793a401 839 if (pos->offset != -1) {
887c0066 840 bpos->idx_asm = browser.nr_asm_entries++;
97148a97
ACM
841 /*
842 * FIXME: short term bandaid to cope with assembly
843 * routines that comes with labels in the same column
844 * as the address in objdump, sigh.
845 *
846 * E.g. copy_user_generic_unrolled
847 */
848 if (pos->offset < (s64)size)
849 browser.offsets[pos->offset] = pos;
b793a401 850 } else
887c0066 851 bpos->idx_asm = -1;
92221162
ACM
852 }
853
b793a401
ACM
854 annotate_browser__mark_jump_targets(&browser, size);
855
2402e4a9 856 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
83b1f2aa 857 browser.max_addr_width = hex_width(sym->end);
2402e4a9 858 browser.jumps_width = width_jumps(browser.max_jump_sources);
0361fc25 859 browser.b.nr_entries = browser.nr_entries;
db9a9cbc 860 browser.b.entries = &notes->src->source,
92221162 861 browser.b.width += 18; /* Percentage */
d04b35f8 862 ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
ce6f4fab 863 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
211ef127 864 list_del(&pos->node);
29ed6e76 865 disasm_line__free(pos);
211ef127 866 }
b793a401
ACM
867
868out_free_offsets:
869 free(browser.offsets);
211ef127
ACM
870 return ret;
871}
This page took 0.18169 seconds and 5 git commands to generate.