blob: 4deea6aaf9274f65887997fcd175fe9fd3bfc459 [file] [log] [blame]
Namhyung Kimaca7a942012-04-04 00:14:26 -07001#include "../../util/util.h"
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -03002#include "../browser.h"
3#include "../helpline.h"
4#include "../libslang.h"
Arnaldo Carvalho de Meloae557952011-10-26 08:00:55 -02005#include "../ui.h"
6#include "../util.h"
Namhyung Kimaca7a942012-04-04 00:14:26 -07007#include "../../util/annotate.h"
8#include "../../util/hist.h"
9#include "../../util/sort.h"
10#include "../../util/symbol.h"
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -030011#include <pthread.h>
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -020012#include <newt.h>
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -030013
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -030014struct browser_disasm_line {
15 struct rb_node rb_node;
16 double percent;
17 u32 idx;
18 int idx_asm;
Arnaldo Carvalho de Melo7d5b12f2012-05-12 13:40:52 -030019 int jump_sources;
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -030020};
21
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -030022static struct annotate_browser_opt {
23 bool hide_src_code,
24 use_offset,
25 jump_arrows,
26 show_nr_jumps;
27} annotate_browser__opts = {
28 .use_offset = true,
29 .jump_arrows = true,
30};
31
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -030032struct annotate_browser {
33 struct ui_browser b;
34 struct rb_root entries;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -030035 struct rb_node *curr_hot;
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -030036 struct disasm_line *selection;
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -030037 struct disasm_line **offsets;
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -030038 u64 start;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -030039 int nr_asm_entries;
40 int nr_entries;
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -030041 int max_jump_sources;
42 int nr_jumps;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -030043 bool searching_backwards;
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -030044 u8 addr_width;
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -030045 u8 jumps_width;
46 u8 target_width;
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -030047 u8 min_addr_width;
48 u8 max_addr_width;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -030049 char search_bf[128];
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -030050};
51
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -030052static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -030053{
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -030054 return (struct browser_disasm_line *)(dl + 1);
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -030055}
56
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -030057static bool disasm_line__filter(struct ui_browser *browser __used, void *entry)
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -030058{
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -030059 if (annotate_browser__opts.hide_src_code) {
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -030060 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
61 return dl->offset == -1;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -030062 }
63
64 return false;
65}
66
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -030067static int annotate_browser__jumps_percent_color(struct annotate_browser *browser,
68 int nr, bool current)
69{
70 if (current && (!browser->b.use_navkeypressed || browser->b.navkeypressed))
71 return HE_COLORSET_SELECTED;
72 if (nr == browser->max_jump_sources)
73 return HE_COLORSET_TOP;
74 if (nr > 1)
75 return HE_COLORSET_MEDIUM;
76 return HE_COLORSET_NORMAL;
77}
78
79static int annotate_browser__set_jumps_percent_color(struct annotate_browser *browser,
80 int nr, bool current)
81{
82 int color = annotate_browser__jumps_percent_color(browser, nr, current);
83 return ui_browser__set_color(&browser->b, color);
84}
85
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030086static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -030087{
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030088 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -030089 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -030090 struct browser_disasm_line *bdl = disasm_line__browser(dl);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030091 bool current_entry = ui_browser__is_current_entry(browser, row);
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -030092 bool change_color = (!annotate_browser__opts.hide_src_code &&
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030093 (!current_entry || (browser->use_navkeypressed &&
94 !browser->navkeypressed)));
95 int width = browser->width, printed;
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -030096 char bf[256];
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -030097
Arnaldo Carvalho de Melo0822cc82012-04-27 17:13:53 -030098 if (dl->offset != -1 && bdl->percent != 0.0) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -030099 ui_browser__set_percent_color(browser, bdl->percent, current_entry);
Arnaldo Carvalho de Melo0822cc82012-04-27 17:13:53 -0300100 slsmg_printf("%6.2f ", bdl->percent);
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300101 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300102 ui_browser__set_percent_color(browser, 0, current_entry);
Arnaldo Carvalho de Melo0822cc82012-04-27 17:13:53 -0300103 slsmg_write_nstring(" ", 7);
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300104 }
105
Arnaldo Carvalho de Melocf2dacc2012-04-19 15:19:17 -0300106 SLsmg_write_char(' ');
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200107
108 /* The scroll bar isn't being used */
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300109 if (!browser->navkeypressed)
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200110 width += 1;
111
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300112 if (!*dl->line)
Arnaldo Carvalho de Melo0822cc82012-04-27 17:13:53 -0300113 slsmg_write_nstring(" ", width - 7);
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300114 else if (dl->offset == -1) {
115 printed = scnprintf(bf, sizeof(bf), "%*s ",
116 ab->addr_width, " ");
117 slsmg_write_nstring(bf, printed);
118 slsmg_write_nstring(dl->line, width - printed - 6);
119 } else {
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300120 u64 addr = dl->offset;
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300121 int color = -1;
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -0300122
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300123 if (!annotate_browser__opts.use_offset)
Arnaldo Carvalho de Meloe235f3f2012-04-02 13:21:55 -0300124 addr += ab->start;
125
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300126 if (!annotate_browser__opts.use_offset) {
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300127 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
Arnaldo Carvalho de Melo61e04b32012-04-19 13:15:24 -0300128 } else {
Arnaldo Carvalho de Melo7d5b12f2012-05-12 13:40:52 -0300129 if (bdl->jump_sources) {
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300130 if (annotate_browser__opts.show_nr_jumps) {
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300131 int prev;
132 printed = scnprintf(bf, sizeof(bf), "%*d ",
133 ab->jumps_width,
134 bdl->jump_sources);
135 prev = annotate_browser__set_jumps_percent_color(ab, bdl->jump_sources,
136 current_entry);
137 slsmg_write_nstring(bf, printed);
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300138 ui_browser__set_color(browser, prev);
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300139 }
140
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300141 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300142 ab->target_width, addr);
Arnaldo Carvalho de Melo61e04b32012-04-19 13:15:24 -0300143 } else {
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300144 printed = scnprintf(bf, sizeof(bf), "%*s ",
145 ab->addr_width, " ");
Arnaldo Carvalho de Melo61e04b32012-04-19 13:15:24 -0300146 }
147 }
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300148
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -0300149 if (change_color)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300150 color = ui_browser__set_color(browser, HE_COLORSET_ADDR);
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -0300151 slsmg_write_nstring(bf, printed);
152 if (change_color)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300153 ui_browser__set_color(browser, color);
Arnaldo Carvalho de Melo28548d72012-04-19 10:16:27 -0300154 if (dl->ins && dl->ins->ops->scnprintf) {
Arnaldo Carvalho de Melo51a0d452012-04-20 15:40:20 -0300155 if (ins__is_jump(dl->ins)) {
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300156 bool fwd = dl->ops.target.offset > (u64)dl->offset;
Arnaldo Carvalho de Melo51a0d452012-04-20 15:40:20 -0300157
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300158 ui_browser__write_graph(browser, fwd ? SLSMG_DARROW_CHAR :
Arnaldo Carvalho de Melo59d038d2012-04-20 16:26:14 -0300159 SLSMG_UARROW_CHAR);
Arnaldo Carvalho de Melo51a0d452012-04-20 15:40:20 -0300160 SLsmg_write_char(' ');
Arnaldo Carvalho de Melo88298f52012-04-27 15:10:54 -0300161 } else if (ins__is_call(dl->ins)) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300162 ui_browser__write_graph(browser, SLSMG_RARROW_CHAR);
Arnaldo Carvalho de Melo88298f52012-04-27 15:10:54 -0300163 SLsmg_write_char(' ');
Arnaldo Carvalho de Melo51a0d452012-04-20 15:40:20 -0300164 } else {
165 slsmg_write_nstring(" ", 2);
166 }
Arnaldo Carvalho de Melo4ea08b52012-04-20 15:51:40 -0300167 } else {
168 if (strcmp(dl->name, "retq")) {
169 slsmg_write_nstring(" ", 2);
170 } else {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300171 ui_browser__write_graph(browser, SLSMG_LARROW_CHAR);
Arnaldo Carvalho de Melo4ea08b52012-04-20 15:51:40 -0300172 SLsmg_write_char(' ');
173 }
Arnaldo Carvalho de Melo4ea08b52012-04-20 15:51:40 -0300174 }
175
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300176 disasm_line__scnprintf(dl, bf, sizeof(bf), !annotate_browser__opts.use_offset);
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300177 slsmg_write_nstring(bf, width - 10 - printed);
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -0300178 }
Arnaldo Carvalho de Melob99976e2011-02-09 13:59:14 -0200179
Namhyung Kim58e817d2012-02-23 17:46:20 +0900180 if (current_entry)
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300181 ab->selection = dl;
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300182}
183
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300184static void annotate_browser__draw_current_jump(struct ui_browser *browser)
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300185{
186 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300187 struct disasm_line *cursor = ab->selection, *target;
188 struct browser_disasm_line *btarget, *bcursor;
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300189 unsigned int from, to;
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300190
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300191 if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) ||
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300192 !disasm_line__has_offset(cursor))
193 return;
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300194
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300195 target = ab->offsets[cursor->ops.target.offset];
196 if (!target)
197 return;
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300198
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300199 bcursor = disasm_line__browser(cursor);
200 btarget = disasm_line__browser(target);
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300201
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300202 if (annotate_browser__opts.hide_src_code) {
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300203 from = bcursor->idx_asm;
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300204 to = btarget->idx_asm;
205 } else {
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300206 from = (u64)bcursor->idx;
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300207 to = (u64)btarget->idx;
208 }
209
210 ui_browser__set_color(browser, HE_COLORSET_CODE);
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300211 __ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to);
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300212}
213
214static unsigned int annotate_browser__refresh(struct ui_browser *browser)
215{
216 int ret = ui_browser__list_head_refresh(browser);
217
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300218 if (annotate_browser__opts.jump_arrows)
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300219 annotate_browser__draw_current_jump(browser);
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300220
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300221 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
222 __ui_browser__vline(browser, 7, 0, browser->height - 1);
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300223 return ret;
224}
225
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300226static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx)
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300227{
228 double percent = 0.0;
229
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300230 if (dl->offset != -1) {
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300231 int len = sym->end - sym->start;
232 unsigned int hits = 0;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200233 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -0200234 struct source_line *src_line = notes->src->lines;
Arnaldo Carvalho de Melo2f525d02011-02-04 13:43:24 -0200235 struct sym_hist *h = annotation__histogram(notes, evidx);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300236 s64 offset = dl->offset;
237 struct disasm_line *next;
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300238
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300239 next = disasm__get_next_ip_line(&notes->src->source, dl);
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300240 while (offset < (s64)len &&
241 (next == NULL || offset < next->offset)) {
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200242 if (src_line) {
243 percent += src_line[offset].percent;
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300244 } else
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200245 hits += h->addr[offset];
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300246
247 ++offset;
248 }
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200249 /*
250 * If the percentage wasn't already calculated in
251 * symbol__get_source_line, do it now:
252 */
253 if (src_line == NULL && h->sum)
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300254 percent = 100.0 * hits / h->sum;
255 }
256
257 return percent;
258}
259
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300260static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl)
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300261{
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300262 struct rb_node **p = &root->rb_node;
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300263 struct rb_node *parent = NULL;
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300264 struct browser_disasm_line *l;
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300265
266 while (*p != NULL) {
267 parent = *p;
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300268 l = rb_entry(parent, struct browser_disasm_line, rb_node);
269 if (bdl->percent < l->percent)
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300270 p = &(*p)->rb_left;
271 else
272 p = &(*p)->rb_right;
273 }
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300274 rb_link_node(&bdl->rb_node, parent, p);
275 rb_insert_color(&bdl->rb_node, root);
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300276}
277
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300278static void annotate_browser__set_top(struct annotate_browser *browser,
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300279 struct disasm_line *pos, u32 idx)
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300280{
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300281 unsigned back;
282
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300283 ui_browser__refresh_dimensions(&browser->b);
284 back = browser->b.height / 2;
285 browser->b.top_idx = browser->b.index = idx;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300286
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300287 while (browser->b.top_idx != 0 && back != 0) {
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300288 pos = list_entry(pos->node.prev, struct disasm_line, node);
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300289
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300290 if (disasm_line__filter(&browser->b, &pos->node))
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300291 continue;
292
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300293 --browser->b.top_idx;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300294 --back;
295 }
296
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300297 browser->b.top = pos;
298 browser->b.navkeypressed = true;
Arnaldo Carvalho de Melob0ffb2c2012-04-03 15:32:45 -0300299}
300
301static void annotate_browser__set_rb_top(struct annotate_browser *browser,
302 struct rb_node *nd)
303{
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300304 struct browser_disasm_line *bpos;
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300305 struct disasm_line *pos;
Arnaldo Carvalho de Meloa44b45f2012-05-29 20:49:14 -0300306 u32 idx;
Arnaldo Carvalho de Melob0ffb2c2012-04-03 15:32:45 -0300307
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300308 bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
309 pos = ((struct disasm_line *)bpos) - 1;
Arnaldo Carvalho de Meloa44b45f2012-05-29 20:49:14 -0300310 idx = bpos->idx;
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300311 if (annotate_browser__opts.hide_src_code)
Arnaldo Carvalho de Meloa44b45f2012-05-29 20:49:14 -0300312 idx = bpos->idx_asm;
313 annotate_browser__set_top(browser, pos, idx);
Arnaldo Carvalho de Melob0ffb2c2012-04-03 15:32:45 -0300314 browser->curr_hot = nd;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300315}
316
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300317static void annotate_browser__calc_percent(struct annotate_browser *browser,
318 int evidx)
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300319{
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300320 struct map_symbol *ms = browser->b.priv;
321 struct symbol *sym = ms->sym;
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300322 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300323 struct disasm_line *pos;
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300324
325 browser->entries = RB_ROOT;
326
327 pthread_mutex_lock(&notes->lock);
328
329 list_for_each_entry(pos, &notes->src->source, node) {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300330 struct browser_disasm_line *bpos = disasm_line__browser(pos);
331 bpos->percent = disasm_line__calc_percent(pos, sym, evidx);
332 if (bpos->percent < 0.01) {
333 RB_CLEAR_NODE(&bpos->rb_node);
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300334 continue;
335 }
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300336 disasm_rb_tree__insert(&browser->entries, bpos);
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300337 }
338 pthread_mutex_unlock(&notes->lock);
339
340 browser->curr_hot = rb_last(&browser->entries);
341}
342
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300343static bool annotate_browser__toggle_source(struct annotate_browser *browser)
344{
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300345 struct disasm_line *dl;
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300346 struct browser_disasm_line *bdl;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300347 off_t offset = browser->b.index - browser->b.top_idx;
348
349 browser->b.seek(&browser->b, offset, SEEK_CUR);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300350 dl = list_entry(browser->b.top, struct disasm_line, node);
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300351 bdl = disasm_line__browser(dl);
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300352
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300353 if (annotate_browser__opts.hide_src_code) {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300354 if (bdl->idx_asm < offset)
355 offset = bdl->idx;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300356
357 browser->b.nr_entries = browser->nr_entries;
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300358 annotate_browser__opts.hide_src_code = false;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300359 browser->b.seek(&browser->b, -offset, SEEK_CUR);
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300360 browser->b.top_idx = bdl->idx - offset;
361 browser->b.index = bdl->idx;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300362 } else {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300363 if (bdl->idx_asm < 0) {
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300364 ui_helpline__puts("Only available for assembly lines.");
365 browser->b.seek(&browser->b, -offset, SEEK_CUR);
366 return false;
367 }
368
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300369 if (bdl->idx_asm < offset)
370 offset = bdl->idx_asm;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300371
372 browser->b.nr_entries = browser->nr_asm_entries;
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300373 annotate_browser__opts.hide_src_code = true;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300374 browser->b.seek(&browser->b, -offset, SEEK_CUR);
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300375 browser->b.top_idx = bdl->idx_asm - offset;
376 browser->b.index = bdl->idx_asm;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300377 }
378
379 return true;
380}
381
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300382static void annotate_browser__init_asm_mode(struct annotate_browser *browser)
383{
384 ui_browser__reset_index(&browser->b);
385 browser->b.nr_entries = browser->nr_asm_entries;
386}
387
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300388static bool annotate_browser__callq(struct annotate_browser *browser,
389 int evidx, void (*timer)(void *arg),
390 void *arg, int delay_secs)
391{
392 struct map_symbol *ms = browser->b.priv;
Arnaldo Carvalho de Melo657bcaf2012-04-15 20:12:07 -0300393 struct disasm_line *dl = browser->selection;
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300394 struct symbol *sym = ms->sym;
395 struct annotation *notes;
396 struct symbol *target;
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300397 u64 ip;
398
Arnaldo Carvalho de Melod86b0592012-04-18 16:07:38 -0300399 if (!ins__is_call(dl->ins))
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300400 return false;
401
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300402 ip = ms->map->map_ip(ms->map, dl->ops.target.addr);
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300403 target = map__find_symbol(ms->map, ip, NULL);
404 if (target == NULL) {
405 ui_helpline__puts("The called function was not found.");
406 return true;
407 }
408
409 notes = symbol__annotation(target);
410 pthread_mutex_lock(&notes->lock);
411
412 if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
413 pthread_mutex_unlock(&notes->lock);
414 ui__warning("Not enough memory for annotating '%s' symbol!\n",
415 target->name);
416 return true;
417 }
418
419 pthread_mutex_unlock(&notes->lock);
420 symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs);
421 ui_browser__show_title(&browser->b, sym->name);
422 return true;
423}
424
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300425static
426struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
427 s64 offset, s64 *idx)
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300428{
429 struct map_symbol *ms = browser->b.priv;
430 struct symbol *sym = ms->sym;
431 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300432 struct disasm_line *pos;
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300433
434 *idx = 0;
435 list_for_each_entry(pos, &notes->src->source, node) {
436 if (pos->offset == offset)
437 return pos;
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300438 if (!disasm_line__filter(&browser->b, &pos->node))
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300439 ++*idx;
440 }
441
442 return NULL;
443}
444
445static bool annotate_browser__jump(struct annotate_browser *browser)
446{
Arnaldo Carvalho de Melo657bcaf2012-04-15 20:12:07 -0300447 struct disasm_line *dl = browser->selection;
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300448 s64 idx;
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300449
Arnaldo Carvalho de Melod86b0592012-04-18 16:07:38 -0300450 if (!ins__is_jump(dl->ins))
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300451 return false;
452
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300453 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300454 if (dl == NULL) {
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300455 ui_helpline__puts("Invallid jump offset");
456 return true;
457 }
458
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300459 annotate_browser__set_top(browser, dl, idx);
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300460
461 return true;
462}
463
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300464static
465struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
466 char *s, s64 *idx)
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300467{
468 struct map_symbol *ms = browser->b.priv;
469 struct symbol *sym = ms->sym;
470 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300471 struct disasm_line *pos = browser->selection;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300472
473 *idx = browser->b.index;
474 list_for_each_entry_continue(pos, &notes->src->source, node) {
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300475 if (disasm_line__filter(&browser->b, &pos->node))
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300476 continue;
477
478 ++*idx;
479
480 if (pos->line && strstr(pos->line, s) != NULL)
481 return pos;
482 }
483
484 return NULL;
485}
486
487static bool __annotate_browser__search(struct annotate_browser *browser)
488{
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300489 struct disasm_line *dl;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300490 s64 idx;
491
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300492 dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
493 if (dl == NULL) {
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300494 ui_helpline__puts("String not found!");
495 return false;
496 }
497
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300498 annotate_browser__set_top(browser, dl, idx);
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300499 browser->searching_backwards = false;
500 return true;
501}
502
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300503static
504struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
505 char *s, s64 *idx)
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300506{
507 struct map_symbol *ms = browser->b.priv;
508 struct symbol *sym = ms->sym;
509 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300510 struct disasm_line *pos = browser->selection;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300511
512 *idx = browser->b.index;
513 list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300514 if (disasm_line__filter(&browser->b, &pos->node))
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300515 continue;
516
517 --*idx;
518
519 if (pos->line && strstr(pos->line, s) != NULL)
520 return pos;
521 }
522
523 return NULL;
524}
525
526static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
527{
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300528 struct disasm_line *dl;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300529 s64 idx;
530
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300531 dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
532 if (dl == NULL) {
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300533 ui_helpline__puts("String not found!");
534 return false;
535 }
536
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300537 annotate_browser__set_top(browser, dl, idx);
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300538 browser->searching_backwards = true;
539 return true;
540}
541
542static bool annotate_browser__search_window(struct annotate_browser *browser,
543 int delay_secs)
544{
545 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
546 "ENTER: OK, ESC: Cancel",
547 delay_secs * 2) != K_ENTER ||
548 !*browser->search_bf)
549 return false;
550
551 return true;
552}
553
554static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
555{
556 if (annotate_browser__search_window(browser, delay_secs))
557 return __annotate_browser__search(browser);
558
559 return false;
560}
561
562static bool annotate_browser__continue_search(struct annotate_browser *browser,
563 int delay_secs)
564{
565 if (!*browser->search_bf)
566 return annotate_browser__search(browser, delay_secs);
567
568 return __annotate_browser__search(browser);
569}
570
571static bool annotate_browser__search_reverse(struct annotate_browser *browser,
572 int delay_secs)
573{
574 if (annotate_browser__search_window(browser, delay_secs))
575 return __annotate_browser__search_reverse(browser);
576
577 return false;
578}
579
580static
581bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
582 int delay_secs)
583{
584 if (!*browser->search_bf)
585 return annotate_browser__search_reverse(browser, delay_secs);
586
587 return __annotate_browser__search_reverse(browser);
588}
589
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300590static void annotate_browser__update_addr_width(struct annotate_browser *browser)
591{
592 if (annotate_browser__opts.use_offset)
593 browser->target_width = browser->min_addr_width;
594 else
595 browser->target_width = browser->max_addr_width;
596
597 browser->addr_width = browser->target_width;
598
599 if (annotate_browser__opts.show_nr_jumps)
600 browser->addr_width += browser->jumps_width + 1;
601}
602
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300603static int annotate_browser__run(struct annotate_browser *browser, int evidx,
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200604 void(*timer)(void *arg),
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300605 void *arg, int delay_secs)
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300606{
607 struct rb_node *nd = NULL;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300608 struct map_symbol *ms = browser->b.priv;
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300609 struct symbol *sym = ms->sym;
Arnaldo Carvalho de Melo54e7a4e2012-05-12 16:36:55 -0300610 const char *help = "Press 'h' for help on key bindings";
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300611 int key;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300612
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300613 if (ui_browser__show(&browser->b, sym->name, help) < 0)
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300614 return -1;
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300615
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300616 annotate_browser__calc_percent(browser, evidx);
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300617
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300618 if (browser->curr_hot) {
619 annotate_browser__set_rb_top(browser, browser->curr_hot);
620 browser->b.navkeypressed = false;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300621 }
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300622
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300623 nd = browser->curr_hot;
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300624
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300625 while (1) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300626 key = ui_browser__run(&browser->b, delay_secs);
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300627
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300628 if (delay_secs != 0) {
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300629 annotate_browser__calc_percent(browser, evidx);
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300630 /*
631 * Current line focus got out of the list of most active
632 * lines, NULL it so that if TAB|UNTAB is pressed, we
633 * move to curr_hot (current hottest line).
634 */
635 if (nd != NULL && RB_EMPTY_NODE(nd))
636 nd = NULL;
637 }
638
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300639 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200640 case K_TIMER:
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300641 if (timer != NULL)
642 timer(arg);
643
644 if (delay_secs != 0)
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300645 symbol__annotate_decay_histogram(sym, evidx);
646 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200647 case K_TAB:
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300648 if (nd != NULL) {
649 nd = rb_prev(nd);
650 if (nd == NULL)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300651 nd = rb_last(&browser->entries);
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300652 } else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300653 nd = browser->curr_hot;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300654 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200655 case K_UNTAB:
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300656 if (nd != NULL)
657 nd = rb_next(nd);
658 if (nd == NULL)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300659 nd = rb_first(&browser->entries);
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300660 else
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300661 nd = browser->curr_hot;
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300662 break;
Arnaldo Carvalho de Melo54e7a4e2012-05-12 16:36:55 -0300663 case K_F1:
Namhyung Kimef7c5372012-02-23 17:46:21 +0900664 case 'h':
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300665 ui_browser__help_window(&browser->b,
Arnaldo Carvalho de Melo54e7a4e2012-05-12 16:36:55 -0300666 "UP/DOWN/PGUP\n"
667 "PGDN/SPACE Navigate\n"
668 "q/ESC/CTRL+C Exit\n\n"
669 "-> Go to target\n"
670 "<- Exit\n"
671 "h Cycle thru hottest instructions\n"
672 "j Toggle showing jump to target arrows\n"
673 "J Toggle showing number of jump sources on targets\n"
674 "n Search next string\n"
675 "o Toggle disassembler output/simplified view\n"
676 "s Toggle source code view\n"
677 "/ Search string\n"
678 "? Search previous string\n");
679 continue;
680 case 'H':
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300681 nd = browser->curr_hot;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300682 break;
Namhyung Kimef7c5372012-02-23 17:46:21 +0900683 case 's':
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300684 if (annotate_browser__toggle_source(browser))
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300685 ui_helpline__puts(help);
686 continue;
Arnaldo Carvalho de Meloe235f3f2012-04-02 13:21:55 -0300687 case 'o':
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300688 annotate_browser__opts.use_offset = !annotate_browser__opts.use_offset;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300689 annotate_browser__update_addr_width(browser);
Arnaldo Carvalho de Meloe235f3f2012-04-02 13:21:55 -0300690 continue;
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300691 case 'j':
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300692 annotate_browser__opts.jump_arrows = !annotate_browser__opts.jump_arrows;
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300693 continue;
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300694 case 'J':
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300695 annotate_browser__opts.show_nr_jumps = !annotate_browser__opts.show_nr_jumps;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300696 annotate_browser__update_addr_width(browser);
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300697 continue;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300698 case '/':
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300699 if (annotate_browser__search(browser, delay_secs)) {
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300700show_help:
701 ui_helpline__puts(help);
702 }
703 continue;
704 case 'n':
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300705 if (browser->searching_backwards ?
706 annotate_browser__continue_search_reverse(browser, delay_secs) :
707 annotate_browser__continue_search(browser, delay_secs))
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300708 goto show_help;
709 continue;
710 case '?':
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300711 if (annotate_browser__search_reverse(browser, delay_secs))
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300712 goto show_help;
713 continue;
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300714 case 'D': {
715 static int seq;
716 ui_helpline__pop();
717 ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300718 seq++, browser->b.nr_entries,
719 browser->b.height,
720 browser->b.index,
721 browser->b.top_idx,
722 browser->nr_asm_entries);
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300723 }
724 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200725 case K_ENTER:
726 case K_RIGHT:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300727 if (browser->selection == NULL)
Arnaldo Carvalho de Melo234a5372011-10-06 09:45:29 -0300728 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300729 else if (browser->selection->offset == -1)
Arnaldo Carvalho de Melo234a5372011-10-06 09:45:29 -0300730 ui_helpline__puts("Actions are only available for assembly lines.");
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300731 else if (!browser->selection->ins) {
732 if (strcmp(browser->selection->name, "retq"))
Arnaldo Carvalho de Meloc4cceae2012-04-20 15:57:15 -0300733 goto show_sup_ins;
734 goto out;
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300735 } else if (!(annotate_browser__jump(browser) ||
736 annotate_browser__callq(browser, evidx, timer, arg, delay_secs))) {
Arnaldo Carvalho de Meloc4cceae2012-04-20 15:57:15 -0300737show_sup_ins:
738 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
739 }
Arnaldo Carvalho de Melofe46e642011-10-19 13:18:13 -0200740 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200741 case K_LEFT:
742 case K_ESC:
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -0300743 case 'q':
744 case CTRL('c'):
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300745 goto out;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -0300746 default:
747 continue;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300748 }
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300749
750 if (nd != NULL)
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300751 annotate_browser__set_rb_top(browser, nd);
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300752 }
753out:
Arnaldo Carvalho de Melo05e8b082012-05-29 22:42:18 -0300754 ui_browser__hide(&browser->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300755 return key;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300756}
757
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200758int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300759 void(*timer)(void *arg), void *arg, int delay_secs)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200760{
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200761 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300762 timer, arg, delay_secs);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200763}
764
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300765static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
766 size_t size)
767{
768 u64 offset;
769
770 for (offset = 0; offset < size; ++offset) {
771 struct disasm_line *dl = browser->offsets[offset], *dlt;
772 struct browser_disasm_line *bdlt;
773
Arnaldo Carvalho de Melo38b31bd2012-04-25 14:18:42 -0300774 if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
775 !disasm_line__has_offset(dl))
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300776 continue;
777
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300778 if (dl->ops.target.offset >= size) {
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300779 ui__error("jump to after symbol!\n"
780 "size: %zx, jump target: %" PRIx64,
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300781 size, dl->ops.target.offset);
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300782 continue;
783 }
784
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300785 dlt = browser->offsets[dl->ops.target.offset];
Arnaldo Carvalho de Melo9481ede2012-04-25 07:48:42 -0300786 /*
787 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
788 * have to adjust to the previous offset?
789 */
790 if (dlt == NULL)
791 continue;
792
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300793 bdlt = disasm_line__browser(dlt);
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300794 if (++bdlt->jump_sources > browser->max_jump_sources)
795 browser->max_jump_sources = bdlt->jump_sources;
796
797 ++browser->nr_jumps;
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300798 }
799
800}
801
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300802static inline int width_jumps(int n)
803{
804 if (n >= 100)
805 return 5;
806 if (n / 10)
807 return 2;
808 return 1;
809}
810
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300811int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200812 void(*timer)(void *arg), void *arg,
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300813 int delay_secs)
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300814{
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300815 struct disasm_line *pos, *n;
Lin Mingdb9a9cbc2011-04-08 14:31:26 +0800816 struct annotation *notes;
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300817 const size_t size = symbol__size(sym);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300818 struct map_symbol ms = {
819 .map = map,
820 .sym = sym,
821 };
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300822 struct annotate_browser browser = {
823 .b = {
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300824 .refresh = annotate_browser__refresh,
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300825 .seek = ui_browser__list_head_seek,
826 .write = annotate_browser__write,
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300827 .filter = disasm_line__filter,
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300828 .priv = &ms,
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200829 .use_navkeypressed = true,
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300830 },
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300831 };
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300832 int ret = -1;
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300833
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200834 if (sym == NULL)
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300835 return -1;
836
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200837 if (map->dso->annotate_warned)
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300838 return -1;
839
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300840 browser.offsets = zalloc(size * sizeof(struct disasm_line *));
841 if (browser.offsets == NULL) {
842 ui__error("Not enough memory!");
843 return -1;
844 }
845
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300846 if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
Arnaldo Carvalho de Meloae557952011-10-26 08:00:55 -0200847 ui__error("%s", ui_helpline__last_msg);
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300848 goto out_free_offsets;
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300849 }
850
851 ui_helpline__push("Press <- or ESC to exit");
852
Lin Mingdb9a9cbc2011-04-08 14:31:26 +0800853 notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -0300854 browser.start = map__rip_2objdump(map, sym->start);
Lin Mingdb9a9cbc2011-04-08 14:31:26 +0800855
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -0200856 list_for_each_entry(pos, &notes->src->source, node) {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300857 struct browser_disasm_line *bpos;
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300858 size_t line_len = strlen(pos->line);
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300859
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300860 if (browser.b.width < line_len)
861 browser.b.width = line_len;
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300862 bpos = disasm_line__browser(pos);
863 bpos->idx = browser.nr_entries++;
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300864 if (pos->offset != -1) {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300865 bpos->idx_asm = browser.nr_asm_entries++;
Arnaldo Carvalho de Melo97148a92012-04-20 15:17:50 -0300866 /*
867 * FIXME: short term bandaid to cope with assembly
868 * routines that comes with labels in the same column
869 * as the address in objdump, sigh.
870 *
871 * E.g. copy_user_generic_unrolled
872 */
873 if (pos->offset < (s64)size)
874 browser.offsets[pos->offset] = pos;
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300875 } else
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300876 bpos->idx_asm = -1;
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300877 }
878
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300879 annotate_browser__mark_jump_targets(&browser, size);
880
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300881 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300882 browser.max_addr_width = hex_width(sym->end);
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300883 browser.jumps_width = width_jumps(browser.max_jump_sources);
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300884 browser.b.nr_entries = browser.nr_entries;
Lin Mingdb9a9cbc2011-04-08 14:31:26 +0800885 browser.b.entries = &notes->src->source,
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300886 browser.b.width += 18; /* Percentage */
Arnaldo Carvalho de Meloe9823b22012-05-29 21:24:05 -0300887
888 if (annotate_browser__opts.hide_src_code)
889 annotate_browser__init_asm_mode(&browser);
890
891 annotate_browser__update_addr_width(&browser);
892
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200893 ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -0200894 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300895 list_del(&pos->node);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300896 disasm_line__free(pos);
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300897 }
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300898
899out_free_offsets:
900 free(browser.offsets);
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300901 return ret;
902}
Arnaldo Carvalho de Meloc323cf02012-05-29 22:06:30 -0300903
904#define ANNOTATE_CFG(n) \
905 { .name = #n, .value = &annotate_browser__opts.n, }
906
907/*
908 * Keep the entries sorted, they are bsearch'ed
909 */
910static struct annotate__config {
911 const char *name;
912 bool *value;
913} annotate__configs[] = {
914 ANNOTATE_CFG(hide_src_code),
915 ANNOTATE_CFG(jump_arrows),
916 ANNOTATE_CFG(show_nr_jumps),
917 ANNOTATE_CFG(use_offset),
918};
919
920#undef ANNOTATE_CFG
921
922static int annotate_config__cmp(const void *name, const void *cfgp)
923{
924 const struct annotate__config *cfg = cfgp;
925
926 return strcmp(name, cfg->name);
927}
928
929static int annotate__config(const char *var, const char *value, void *data __used)
930{
931 struct annotate__config *cfg;
932 const char *name;
933
934 if (prefixcmp(var, "annotate.") != 0)
935 return 0;
936
937 name = var + 9;
938 cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs),
939 sizeof(struct annotate__config), annotate_config__cmp);
940
941 if (cfg == NULL)
942 return -1;
943
944 *cfg->value = perf_config_bool(name, value);
945 return 0;
946}
947
948void annotate_browser__init(void)
949{
950 perf_config(annotate__config, NULL);
951}