blob: aaf36ce0b6fec2e087abffafc9a5df98cb679320 [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 Melo92221162010-08-09 15:30:40 -030022struct annotate_browser {
23 struct ui_browser b;
24 struct rb_root entries;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -030025 struct rb_node *curr_hot;
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -030026 struct disasm_line *selection;
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -030027 struct disasm_line **offsets;
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -030028 u64 start;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -030029 int nr_asm_entries;
30 int nr_entries;
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -030031 int max_jump_sources;
32 int nr_jumps;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -030033 bool hide_src_code;
Arnaldo Carvalho de Meloe235f3f2012-04-02 13:21:55 -030034 bool use_offset;
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -030035 bool jump_arrows;
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -030036 bool show_nr_jumps;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -030037 bool searching_backwards;
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -030038 u8 addr_width;
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -030039 u8 jumps_width;
40 u8 target_width;
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -030041 u8 min_addr_width;
42 u8 max_addr_width;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -030043 char search_bf[128];
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -030044};
45
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -030046static inline struct browser_disasm_line *disasm_line__browser(struct disasm_line *dl)
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -030047{
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -030048 return (struct browser_disasm_line *)(dl + 1);
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -030049}
50
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -030051static bool disasm_line__filter(struct ui_browser *browser, void *entry)
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -030052{
53 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
54
55 if (ab->hide_src_code) {
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -030056 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
57 return dl->offset == -1;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -030058 }
59
60 return false;
61}
62
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -030063static 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
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -030082static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
83{
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -030084 struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -030085 struct disasm_line *dl = list_entry(entry, struct disasm_line, node);
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -030086 struct browser_disasm_line *bdl = disasm_line__browser(dl);
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -030087 bool current_entry = ui_browser__is_current_entry(self, row);
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -030088 bool change_color = (!ab->hide_src_code &&
89 (!current_entry || (self->use_navkeypressed &&
90 !self->navkeypressed)));
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -030091 int width = self->width, printed;
92 char bf[256];
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -030093
Arnaldo Carvalho de Melo0822cc82012-04-27 17:13:53 -030094 if (dl->offset != -1 && bdl->percent != 0.0) {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -030095 ui_browser__set_percent_color(self, bdl->percent, current_entry);
Arnaldo Carvalho de Melo0822cc82012-04-27 17:13:53 -030096 slsmg_printf("%6.2f ", bdl->percent);
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -030097 } else {
Arnaldo Carvalho de Melo8f9bbc42010-08-11 14:51:47 -030098 ui_browser__set_percent_color(self, 0, current_entry);
Arnaldo Carvalho de Melo0822cc82012-04-27 17:13:53 -030099 slsmg_write_nstring(" ", 7);
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300100 }
101
Arnaldo Carvalho de Melocf2dacc2012-04-19 15:19:17 -0300102 SLsmg_write_char(' ');
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200103
104 /* The scroll bar isn't being used */
105 if (!self->navkeypressed)
106 width += 1;
107
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300108 if (!*dl->line)
Arnaldo Carvalho de Melo0822cc82012-04-27 17:13:53 -0300109 slsmg_write_nstring(" ", width - 7);
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300110 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 {
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300116 u64 addr = dl->offset;
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300117 int color = -1;
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -0300118
Arnaldo Carvalho de Meloe235f3f2012-04-02 13:21:55 -0300119 if (!ab->use_offset)
120 addr += ab->start;
121
Arnaldo Carvalho de Melo61e04b32012-04-19 13:15:24 -0300122 if (!ab->use_offset) {
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300123 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
Arnaldo Carvalho de Melo61e04b32012-04-19 13:15:24 -0300124 } else {
Arnaldo Carvalho de Melo7d5b12f2012-05-12 13:40:52 -0300125 if (bdl->jump_sources) {
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300126 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
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300137 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300138 ab->target_width, addr);
Arnaldo Carvalho de Melo61e04b32012-04-19 13:15:24 -0300139 } else {
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300140 printed = scnprintf(bf, sizeof(bf), "%*s ",
141 ab->addr_width, " ");
Arnaldo Carvalho de Melo61e04b32012-04-19 13:15:24 -0300142 }
143 }
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300144
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -0300145 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);
Arnaldo Carvalho de Melo28548d72012-04-19 10:16:27 -0300150 if (dl->ins && dl->ins->ops->scnprintf) {
Arnaldo Carvalho de Melo51a0d452012-04-20 15:40:20 -0300151 if (ins__is_jump(dl->ins)) {
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300152 bool fwd = dl->ops.target.offset > (u64)dl->offset;
Arnaldo Carvalho de Melo51a0d452012-04-20 15:40:20 -0300153
Arnaldo Carvalho de Melo59d038d2012-04-20 16:26:14 -0300154 ui_browser__write_graph(self, fwd ? SLSMG_DARROW_CHAR :
155 SLSMG_UARROW_CHAR);
Arnaldo Carvalho de Melo51a0d452012-04-20 15:40:20 -0300156 SLsmg_write_char(' ');
Arnaldo Carvalho de Melo88298f52012-04-27 15:10:54 -0300157 } else if (ins__is_call(dl->ins)) {
158 ui_browser__write_graph(self, SLSMG_RARROW_CHAR);
159 SLsmg_write_char(' ');
Arnaldo Carvalho de Melo51a0d452012-04-20 15:40:20 -0300160 } else {
161 slsmg_write_nstring(" ", 2);
162 }
Arnaldo Carvalho de Melo4ea08b52012-04-20 15:51:40 -0300163 } else {
164 if (strcmp(dl->name, "retq")) {
165 slsmg_write_nstring(" ", 2);
166 } else {
Arnaldo Carvalho de Melo59d038d2012-04-20 16:26:14 -0300167 ui_browser__write_graph(self, SLSMG_LARROW_CHAR);
Arnaldo Carvalho de Melo4ea08b52012-04-20 15:51:40 -0300168 SLsmg_write_char(' ');
169 }
Arnaldo Carvalho de Melo4ea08b52012-04-20 15:51:40 -0300170 }
171
Arnaldo Carvalho de Melo54170722012-05-07 18:54:16 -0300172 disasm_line__scnprintf(dl, bf, sizeof(bf), !ab->use_offset);
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300173 slsmg_write_nstring(bf, width - 10 - printed);
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -0300174 }
Arnaldo Carvalho de Melob99976e2011-02-09 13:59:14 -0200175
Namhyung Kim58e817d2012-02-23 17:46:20 +0900176 if (current_entry)
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300177 ab->selection = dl;
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300178}
179
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300180static void annotate_browser__draw_current_jump(struct ui_browser *browser)
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300181{
182 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300183 struct disasm_line *cursor = ab->selection, *target;
184 struct browser_disasm_line *btarget, *bcursor;
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300185 unsigned int from, to;
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300186
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300187 if (!cursor->ins || !ins__is_jump(cursor->ins) ||
188 !disasm_line__has_offset(cursor))
189 return;
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300190
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300191 target = ab->offsets[cursor->ops.target.offset];
192 if (!target)
193 return;
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300194
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300195 bcursor = disasm_line__browser(cursor);
196 btarget = disasm_line__browser(target);
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300197
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300198 if (ab->hide_src_code) {
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300199 from = bcursor->idx_asm;
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300200 to = btarget->idx_asm;
201 } else {
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300202 from = (u64)bcursor->idx;
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300203 to = (u64)btarget->idx;
204 }
205
206 ui_browser__set_color(browser, HE_COLORSET_CODE);
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300207 __ui_browser__line_arrow(browser, 9 + ab->addr_width, from, to);
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300208}
209
210static unsigned int annotate_browser__refresh(struct ui_browser *browser)
211{
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300212 struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300213 int ret = ui_browser__list_head_refresh(browser);
214
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300215 if (ab->jump_arrows)
216 annotate_browser__draw_current_jump(browser);
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300217
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300218 ui_browser__set_color(browser, HE_COLORSET_NORMAL);
219 __ui_browser__vline(browser, 7, 0, browser->height - 1);
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300220 return ret;
221}
222
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300223static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx)
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300224{
225 double percent = 0.0;
226
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300227 if (dl->offset != -1) {
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300228 int len = sym->end - sym->start;
229 unsigned int hits = 0;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200230 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -0200231 struct source_line *src_line = notes->src->lines;
Arnaldo Carvalho de Melo2f525d02011-02-04 13:43:24 -0200232 struct sym_hist *h = annotation__histogram(notes, evidx);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300233 s64 offset = dl->offset;
234 struct disasm_line *next;
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300235
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300236 next = disasm__get_next_ip_line(&notes->src->source, dl);
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300237 while (offset < (s64)len &&
238 (next == NULL || offset < next->offset)) {
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200239 if (src_line) {
240 percent += src_line[offset].percent;
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300241 } else
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200242 hits += h->addr[offset];
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300243
244 ++offset;
245 }
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200246 /*
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)
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300251 percent = 100.0 * hits / h->sum;
252 }
253
254 return percent;
255}
256
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300257static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl)
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300258{
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300259 struct rb_node **p = &root->rb_node;
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300260 struct rb_node *parent = NULL;
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300261 struct browser_disasm_line *l;
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300262
263 while (*p != NULL) {
264 parent = *p;
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300265 l = rb_entry(parent, struct browser_disasm_line, rb_node);
266 if (bdl->percent < l->percent)
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300267 p = &(*p)->rb_left;
268 else
269 p = &(*p)->rb_right;
270 }
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300271 rb_link_node(&bdl->rb_node, parent, p);
272 rb_insert_color(&bdl->rb_node, root);
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300273}
274
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300275static void annotate_browser__set_top(struct annotate_browser *self,
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300276 struct disasm_line *pos, u32 idx)
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300277{
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300278 unsigned back;
279
280 ui_browser__refresh_dimensions(&self->b);
281 back = self->b.height / 2;
Arnaldo Carvalho de Melob0ffb2c2012-04-03 15:32:45 -0300282 self->b.top_idx = self->b.index = idx;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300283
284 while (self->b.top_idx != 0 && back != 0) {
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300285 pos = list_entry(pos->node.prev, struct disasm_line, node);
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300286
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300287 if (disasm_line__filter(&self->b, &pos->node))
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300288 continue;
289
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300290 --self->b.top_idx;
291 --back;
292 }
293
294 self->b.top = pos;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300295 self->b.navkeypressed = true;
Arnaldo Carvalho de Melob0ffb2c2012-04-03 15:32:45 -0300296}
297
298static void annotate_browser__set_rb_top(struct annotate_browser *browser,
299 struct rb_node *nd)
300{
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300301 struct browser_disasm_line *bpos;
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300302 struct disasm_line *pos;
Arnaldo Carvalho de Meloa44b45f2012-05-29 20:49:14 -0300303 u32 idx;
Arnaldo Carvalho de Melob0ffb2c2012-04-03 15:32:45 -0300304
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300305 bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
306 pos = ((struct disasm_line *)bpos) - 1;
Arnaldo Carvalho de Meloa44b45f2012-05-29 20:49:14 -0300307 idx = bpos->idx;
308 if (browser->hide_src_code)
309 idx = bpos->idx_asm;
310 annotate_browser__set_top(browser, pos, idx);
Arnaldo Carvalho de Melob0ffb2c2012-04-03 15:32:45 -0300311 browser->curr_hot = nd;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300312}
313
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300314static void annotate_browser__calc_percent(struct annotate_browser *browser,
315 int evidx)
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300316{
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300317 struct map_symbol *ms = browser->b.priv;
318 struct symbol *sym = ms->sym;
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300319 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300320 struct disasm_line *pos;
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300321
322 browser->entries = RB_ROOT;
323
324 pthread_mutex_lock(&notes->lock);
325
326 list_for_each_entry(pos, &notes->src->source, node) {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300327 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);
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300331 continue;
332 }
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300333 disasm_rb_tree__insert(&browser->entries, bpos);
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300334 }
335 pthread_mutex_unlock(&notes->lock);
336
337 browser->curr_hot = rb_last(&browser->entries);
338}
339
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300340static bool annotate_browser__toggle_source(struct annotate_browser *browser)
341{
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300342 struct disasm_line *dl;
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300343 struct browser_disasm_line *bdl;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300344 off_t offset = browser->b.index - browser->b.top_idx;
345
346 browser->b.seek(&browser->b, offset, SEEK_CUR);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300347 dl = list_entry(browser->b.top, struct disasm_line, node);
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300348 bdl = disasm_line__browser(dl);
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300349
350 if (browser->hide_src_code) {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300351 if (bdl->idx_asm < offset)
352 offset = bdl->idx;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300353
354 browser->b.nr_entries = browser->nr_entries;
355 browser->hide_src_code = false;
356 browser->b.seek(&browser->b, -offset, SEEK_CUR);
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300357 browser->b.top_idx = bdl->idx - offset;
358 browser->b.index = bdl->idx;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300359 } else {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300360 if (bdl->idx_asm < 0) {
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300361 ui_helpline__puts("Only available for assembly lines.");
362 browser->b.seek(&browser->b, -offset, SEEK_CUR);
363 return false;
364 }
365
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300366 if (bdl->idx_asm < offset)
367 offset = bdl->idx_asm;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300368
369 browser->b.nr_entries = browser->nr_asm_entries;
370 browser->hide_src_code = true;
371 browser->b.seek(&browser->b, -offset, SEEK_CUR);
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300372 browser->b.top_idx = bdl->idx_asm - offset;
373 browser->b.index = bdl->idx_asm;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300374 }
375
376 return true;
377}
378
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300379static 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;
Arnaldo Carvalho de Melo657bcaf2012-04-15 20:12:07 -0300384 struct disasm_line *dl = browser->selection;
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300385 struct symbol *sym = ms->sym;
386 struct annotation *notes;
387 struct symbol *target;
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300388 u64 ip;
389
Arnaldo Carvalho de Melod86b0592012-04-18 16:07:38 -0300390 if (!ins__is_call(dl->ins))
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300391 return false;
392
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300393 ip = ms->map->map_ip(ms->map, dl->ops.target.addr);
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300394 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
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300416static
417struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
418 s64 offset, s64 *idx)
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300419{
420 struct map_symbol *ms = browser->b.priv;
421 struct symbol *sym = ms->sym;
422 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300423 struct disasm_line *pos;
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300424
425 *idx = 0;
426 list_for_each_entry(pos, &notes->src->source, node) {
427 if (pos->offset == offset)
428 return pos;
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300429 if (!disasm_line__filter(&browser->b, &pos->node))
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300430 ++*idx;
431 }
432
433 return NULL;
434}
435
436static bool annotate_browser__jump(struct annotate_browser *browser)
437{
Arnaldo Carvalho de Melo657bcaf2012-04-15 20:12:07 -0300438 struct disasm_line *dl = browser->selection;
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300439 s64 idx;
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300440
Arnaldo Carvalho de Melod86b0592012-04-18 16:07:38 -0300441 if (!ins__is_jump(dl->ins))
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300442 return false;
443
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300444 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300445 if (dl == NULL) {
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300446 ui_helpline__puts("Invallid jump offset");
447 return true;
448 }
449
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300450 annotate_browser__set_top(browser, dl, idx);
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300451
452 return true;
453}
454
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300455static
456struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
457 char *s, s64 *idx)
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300458{
459 struct map_symbol *ms = browser->b.priv;
460 struct symbol *sym = ms->sym;
461 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300462 struct disasm_line *pos = browser->selection;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300463
464 *idx = browser->b.index;
465 list_for_each_entry_continue(pos, &notes->src->source, node) {
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300466 if (disasm_line__filter(&browser->b, &pos->node))
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300467 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{
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300480 struct disasm_line *dl;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300481 s64 idx;
482
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300483 dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
484 if (dl == NULL) {
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300485 ui_helpline__puts("String not found!");
486 return false;
487 }
488
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300489 annotate_browser__set_top(browser, dl, idx);
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300490 browser->searching_backwards = false;
491 return true;
492}
493
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300494static
495struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
496 char *s, s64 *idx)
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300497{
498 struct map_symbol *ms = browser->b.priv;
499 struct symbol *sym = ms->sym;
500 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300501 struct disasm_line *pos = browser->selection;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300502
503 *idx = browser->b.index;
504 list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300505 if (disasm_line__filter(&browser->b, &pos->node))
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300506 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{
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300519 struct disasm_line *dl;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300520 s64 idx;
521
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300522 dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
523 if (dl == NULL) {
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300524 ui_helpline__puts("String not found!");
525 return false;
526 }
527
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300528 annotate_browser__set_top(browser, dl, idx);
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300529 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
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300581static int annotate_browser__run(struct annotate_browser *self, int evidx,
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200582 void(*timer)(void *arg),
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300583 void *arg, int delay_secs)
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300584{
585 struct rb_node *nd = NULL;
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300586 struct map_symbol *ms = self->b.priv;
587 struct symbol *sym = ms->sym;
Arnaldo Carvalho de Melo54e7a4e2012-05-12 16:36:55 -0300588 const char *help = "Press 'h' for help on key bindings";
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300589 int key;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300590
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300591 if (ui_browser__show(&self->b, sym->name, help) < 0)
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300592 return -1;
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300593
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300594 annotate_browser__calc_percent(self, evidx);
595
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300596 if (self->curr_hot) {
Arnaldo Carvalho de Melob0ffb2c2012-04-03 15:32:45 -0300597 annotate_browser__set_rb_top(self, self->curr_hot);
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300598 self->b.navkeypressed = false;
599 }
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300600
601 nd = self->curr_hot;
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300602
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300603 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -0300604 key = ui_browser__run(&self->b, delay_secs);
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300605
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300606 if (delay_secs != 0) {
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300607 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
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300617 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200618 case K_TIMER:
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300619 if (timer != NULL)
620 timer(arg);
621
622 if (delay_secs != 0)
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300623 symbol__annotate_decay_histogram(sym, evidx);
624 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200625 case K_TAB:
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300626 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;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300632 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200633 case K_UNTAB:
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300634 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;
Arnaldo Carvalho de Melo54e7a4e2012-05-12 16:36:55 -0300641 case K_F1:
Namhyung Kimef7c5372012-02-23 17:46:21 +0900642 case 'h':
Arnaldo Carvalho de Melo54e7a4e2012-05-12 16:36:55 -0300643 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':
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300659 nd = self->curr_hot;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300660 break;
Namhyung Kimef7c5372012-02-23 17:46:21 +0900661 case 's':
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300662 if (annotate_browser__toggle_source(self))
663 ui_helpline__puts(help);
664 continue;
Arnaldo Carvalho de Meloe235f3f2012-04-02 13:21:55 -0300665 case 'o':
666 self->use_offset = !self->use_offset;
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300667 if (self->use_offset)
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300668 self->target_width = self->min_addr_width;
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300669 else
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300670 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;
Arnaldo Carvalho de Meloe235f3f2012-04-02 13:21:55 -0300675 continue;
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300676 case 'j':
677 self->jump_arrows = !self->jump_arrows;
678 continue;
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300679 case 'J':
680 self->show_nr_jumps = !self->show_nr_jumps;
681 goto update_addr_width;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300682 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;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200698 case K_ENTER:
699 case K_RIGHT:
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300700 if (self->selection == NULL)
Arnaldo Carvalho de Melo234a5372011-10-06 09:45:29 -0300701 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300702 else if (self->selection->offset == -1)
Arnaldo Carvalho de Melo234a5372011-10-06 09:45:29 -0300703 ui_helpline__puts("Actions are only available for assembly lines.");
Arnaldo Carvalho de Meloc4cceae2012-04-20 15:57:15 -0300704 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 }
Arnaldo Carvalho de Melofe46e642011-10-19 13:18:13 -0200713 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200714 case K_LEFT:
715 case K_ESC:
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -0300716 case 'q':
717 case CTRL('c'):
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300718 goto out;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -0300719 default:
720 continue;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300721 }
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300722
723 if (nd != NULL)
Arnaldo Carvalho de Melob0ffb2c2012-04-03 15:32:45 -0300724 annotate_browser__set_rb_top(self, nd);
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300725 }
726out:
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300727 ui_browser__hide(&self->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300728 return key;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300729}
730
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200731int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300732 void(*timer)(void *arg), void *arg, int delay_secs)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200733{
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200734 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300735 timer, arg, delay_secs);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200736}
737
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300738static 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
Arnaldo Carvalho de Melo38b31bd2012-04-25 14:18:42 -0300747 if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
748 !disasm_line__has_offset(dl))
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300749 continue;
750
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300751 if (dl->ops.target.offset >= size) {
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300752 ui__error("jump to after symbol!\n"
753 "size: %zx, jump target: %" PRIx64,
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300754 size, dl->ops.target.offset);
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300755 continue;
756 }
757
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300758 dlt = browser->offsets[dl->ops.target.offset];
Arnaldo Carvalho de Melo9481ede2012-04-25 07:48:42 -0300759 /*
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
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300766 bdlt = disasm_line__browser(dlt);
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300767 if (++bdlt->jump_sources > browser->max_jump_sources)
768 browser->max_jump_sources = bdlt->jump_sources;
769
770 ++browser->nr_jumps;
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300771 }
772
773}
774
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300775static 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
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300784int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200785 void(*timer)(void *arg), void *arg,
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300786 int delay_secs)
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300787{
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300788 struct disasm_line *pos, *n;
Lin Mingdb9a9cb2011-04-08 14:31:26 +0800789 struct annotation *notes;
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300790 const size_t size = symbol__size(sym);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300791 struct map_symbol ms = {
792 .map = map,
793 .sym = sym,
794 };
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300795 struct annotate_browser browser = {
796 .b = {
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300797 .refresh = annotate_browser__refresh,
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300798 .seek = ui_browser__list_head_seek,
799 .write = annotate_browser__write,
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300800 .filter = disasm_line__filter,
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300801 .priv = &ms,
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200802 .use_navkeypressed = true,
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300803 },
Arnaldo Carvalho de Melo8bf39cb2012-04-19 15:07:46 -0300804 .use_offset = true,
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300805 .jump_arrows = true,
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300806 };
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300807 int ret = -1;
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300808
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200809 if (sym == NULL)
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300810 return -1;
811
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200812 if (map->dso->annotate_warned)
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300813 return -1;
814
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300815 browser.offsets = zalloc(size * sizeof(struct disasm_line *));
816 if (browser.offsets == NULL) {
817 ui__error("Not enough memory!");
818 return -1;
819 }
820
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300821 if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
Arnaldo Carvalho de Meloae557952011-10-26 08:00:55 -0200822 ui__error("%s", ui_helpline__last_msg);
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300823 goto out_free_offsets;
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300824 }
825
826 ui_helpline__push("Press <- or ESC to exit");
827
Lin Mingdb9a9cb2011-04-08 14:31:26 +0800828 notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -0300829 browser.start = map__rip_2objdump(map, sym->start);
Lin Mingdb9a9cb2011-04-08 14:31:26 +0800830
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -0200831 list_for_each_entry(pos, &notes->src->source, node) {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300832 struct browser_disasm_line *bpos;
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300833 size_t line_len = strlen(pos->line);
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300834
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300835 if (browser.b.width < line_len)
836 browser.b.width = line_len;
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300837 bpos = disasm_line__browser(pos);
838 bpos->idx = browser.nr_entries++;
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300839 if (pos->offset != -1) {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300840 bpos->idx_asm = browser.nr_asm_entries++;
Arnaldo Carvalho de Melo97148a92012-04-20 15:17:50 -0300841 /*
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;
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300850 } else
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300851 bpos->idx_asm = -1;
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300852 }
853
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300854 annotate_browser__mark_jump_targets(&browser, size);
855
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300856 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300857 browser.max_addr_width = hex_width(sym->end);
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300858 browser.jumps_width = width_jumps(browser.max_jump_sources);
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300859 browser.b.nr_entries = browser.nr_entries;
Lin Mingdb9a9cb2011-04-08 14:31:26 +0800860 browser.b.entries = &notes->src->source,
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300861 browser.b.width += 18; /* Percentage */
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200862 ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -0200863 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300864 list_del(&pos->node);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300865 disasm_line__free(pos);
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300866 }
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300867
868out_free_offsets:
869 free(browser.offsets);
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300870 return ret;
871}