blob: 6e0ef79be16907a781bcf31be96377671412f440 [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 Melob0ffb2c2012-04-03 15:32:45 -0300303
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300304 bpos = rb_entry(nd, struct browser_disasm_line, rb_node);
305 pos = ((struct disasm_line *)bpos) - 1;
306 annotate_browser__set_top(browser, pos, bpos->idx);
Arnaldo Carvalho de Melob0ffb2c2012-04-03 15:32:45 -0300307 browser->curr_hot = nd;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300308}
309
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300310static void annotate_browser__calc_percent(struct annotate_browser *browser,
311 int evidx)
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300312{
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300313 struct map_symbol *ms = browser->b.priv;
314 struct symbol *sym = ms->sym;
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300315 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300316 struct disasm_line *pos;
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300317
318 browser->entries = RB_ROOT;
319
320 pthread_mutex_lock(&notes->lock);
321
322 list_for_each_entry(pos, &notes->src->source, node) {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300323 struct browser_disasm_line *bpos = disasm_line__browser(pos);
324 bpos->percent = disasm_line__calc_percent(pos, sym, evidx);
325 if (bpos->percent < 0.01) {
326 RB_CLEAR_NODE(&bpos->rb_node);
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300327 continue;
328 }
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300329 disasm_rb_tree__insert(&browser->entries, bpos);
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300330 }
331 pthread_mutex_unlock(&notes->lock);
332
333 browser->curr_hot = rb_last(&browser->entries);
334}
335
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300336static bool annotate_browser__toggle_source(struct annotate_browser *browser)
337{
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300338 struct disasm_line *dl;
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300339 struct browser_disasm_line *bdl;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300340 off_t offset = browser->b.index - browser->b.top_idx;
341
342 browser->b.seek(&browser->b, offset, SEEK_CUR);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300343 dl = list_entry(browser->b.top, struct disasm_line, node);
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300344 bdl = disasm_line__browser(dl);
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300345
346 if (browser->hide_src_code) {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300347 if (bdl->idx_asm < offset)
348 offset = bdl->idx;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300349
350 browser->b.nr_entries = browser->nr_entries;
351 browser->hide_src_code = false;
352 browser->b.seek(&browser->b, -offset, SEEK_CUR);
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300353 browser->b.top_idx = bdl->idx - offset;
354 browser->b.index = bdl->idx;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300355 } else {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300356 if (bdl->idx_asm < 0) {
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300357 ui_helpline__puts("Only available for assembly lines.");
358 browser->b.seek(&browser->b, -offset, SEEK_CUR);
359 return false;
360 }
361
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300362 if (bdl->idx_asm < offset)
363 offset = bdl->idx_asm;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300364
365 browser->b.nr_entries = browser->nr_asm_entries;
366 browser->hide_src_code = true;
367 browser->b.seek(&browser->b, -offset, SEEK_CUR);
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300368 browser->b.top_idx = bdl->idx_asm - offset;
369 browser->b.index = bdl->idx_asm;
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300370 }
371
372 return true;
373}
374
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300375static bool annotate_browser__callq(struct annotate_browser *browser,
376 int evidx, void (*timer)(void *arg),
377 void *arg, int delay_secs)
378{
379 struct map_symbol *ms = browser->b.priv;
Arnaldo Carvalho de Melo657bcaf2012-04-15 20:12:07 -0300380 struct disasm_line *dl = browser->selection;
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300381 struct symbol *sym = ms->sym;
382 struct annotation *notes;
383 struct symbol *target;
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300384 u64 ip;
385
Arnaldo Carvalho de Melod86b0592012-04-18 16:07:38 -0300386 if (!ins__is_call(dl->ins))
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300387 return false;
388
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300389 ip = ms->map->map_ip(ms->map, dl->ops.target.addr);
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300390 target = map__find_symbol(ms->map, ip, NULL);
391 if (target == NULL) {
392 ui_helpline__puts("The called function was not found.");
393 return true;
394 }
395
396 notes = symbol__annotation(target);
397 pthread_mutex_lock(&notes->lock);
398
399 if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
400 pthread_mutex_unlock(&notes->lock);
401 ui__warning("Not enough memory for annotating '%s' symbol!\n",
402 target->name);
403 return true;
404 }
405
406 pthread_mutex_unlock(&notes->lock);
407 symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs);
408 ui_browser__show_title(&browser->b, sym->name);
409 return true;
410}
411
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300412static
413struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
414 s64 offset, s64 *idx)
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300415{
416 struct map_symbol *ms = browser->b.priv;
417 struct symbol *sym = ms->sym;
418 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300419 struct disasm_line *pos;
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300420
421 *idx = 0;
422 list_for_each_entry(pos, &notes->src->source, node) {
423 if (pos->offset == offset)
424 return pos;
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300425 if (!disasm_line__filter(&browser->b, &pos->node))
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300426 ++*idx;
427 }
428
429 return NULL;
430}
431
432static bool annotate_browser__jump(struct annotate_browser *browser)
433{
Arnaldo Carvalho de Melo657bcaf2012-04-15 20:12:07 -0300434 struct disasm_line *dl = browser->selection;
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300435 s64 idx;
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300436
Arnaldo Carvalho de Melod86b0592012-04-18 16:07:38 -0300437 if (!ins__is_jump(dl->ins))
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300438 return false;
439
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300440 dl = annotate_browser__find_offset(browser, dl->ops.target.offset, &idx);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300441 if (dl == NULL) {
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300442 ui_helpline__puts("Invallid jump offset");
443 return true;
444 }
445
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300446 annotate_browser__set_top(browser, dl, idx);
Arnaldo Carvalho de Melo08be4ee2012-04-03 21:35:35 -0300447
448 return true;
449}
450
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300451static
452struct disasm_line *annotate_browser__find_string(struct annotate_browser *browser,
453 char *s, s64 *idx)
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300454{
455 struct map_symbol *ms = browser->b.priv;
456 struct symbol *sym = ms->sym;
457 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300458 struct disasm_line *pos = browser->selection;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300459
460 *idx = browser->b.index;
461 list_for_each_entry_continue(pos, &notes->src->source, node) {
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300462 if (disasm_line__filter(&browser->b, &pos->node))
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300463 continue;
464
465 ++*idx;
466
467 if (pos->line && strstr(pos->line, s) != NULL)
468 return pos;
469 }
470
471 return NULL;
472}
473
474static bool __annotate_browser__search(struct annotate_browser *browser)
475{
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300476 struct disasm_line *dl;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300477 s64 idx;
478
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300479 dl = annotate_browser__find_string(browser, browser->search_bf, &idx);
480 if (dl == NULL) {
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300481 ui_helpline__puts("String not found!");
482 return false;
483 }
484
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300485 annotate_browser__set_top(browser, dl, idx);
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300486 browser->searching_backwards = false;
487 return true;
488}
489
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300490static
491struct disasm_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
492 char *s, s64 *idx)
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300493{
494 struct map_symbol *ms = browser->b.priv;
495 struct symbol *sym = ms->sym;
496 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300497 struct disasm_line *pos = browser->selection;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300498
499 *idx = browser->b.index;
500 list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300501 if (disasm_line__filter(&browser->b, &pos->node))
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300502 continue;
503
504 --*idx;
505
506 if (pos->line && strstr(pos->line, s) != NULL)
507 return pos;
508 }
509
510 return NULL;
511}
512
513static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
514{
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300515 struct disasm_line *dl;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300516 s64 idx;
517
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300518 dl = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
519 if (dl == NULL) {
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300520 ui_helpline__puts("String not found!");
521 return false;
522 }
523
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300524 annotate_browser__set_top(browser, dl, idx);
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300525 browser->searching_backwards = true;
526 return true;
527}
528
529static bool annotate_browser__search_window(struct annotate_browser *browser,
530 int delay_secs)
531{
532 if (ui_browser__input_window("Search", "String: ", browser->search_bf,
533 "ENTER: OK, ESC: Cancel",
534 delay_secs * 2) != K_ENTER ||
535 !*browser->search_bf)
536 return false;
537
538 return true;
539}
540
541static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
542{
543 if (annotate_browser__search_window(browser, delay_secs))
544 return __annotate_browser__search(browser);
545
546 return false;
547}
548
549static bool annotate_browser__continue_search(struct annotate_browser *browser,
550 int delay_secs)
551{
552 if (!*browser->search_bf)
553 return annotate_browser__search(browser, delay_secs);
554
555 return __annotate_browser__search(browser);
556}
557
558static bool annotate_browser__search_reverse(struct annotate_browser *browser,
559 int delay_secs)
560{
561 if (annotate_browser__search_window(browser, delay_secs))
562 return __annotate_browser__search_reverse(browser);
563
564 return false;
565}
566
567static
568bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
569 int delay_secs)
570{
571 if (!*browser->search_bf)
572 return annotate_browser__search_reverse(browser, delay_secs);
573
574 return __annotate_browser__search_reverse(browser);
575}
576
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300577static int annotate_browser__run(struct annotate_browser *self, int evidx,
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200578 void(*timer)(void *arg),
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300579 void *arg, int delay_secs)
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300580{
581 struct rb_node *nd = NULL;
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300582 struct map_symbol *ms = self->b.priv;
583 struct symbol *sym = ms->sym;
Arnaldo Carvalho de Melo54e7a4e2012-05-12 16:36:55 -0300584 const char *help = "Press 'h' for help on key bindings";
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300585 int key;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300586
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300587 if (ui_browser__show(&self->b, sym->name, help) < 0)
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300588 return -1;
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300589
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300590 annotate_browser__calc_percent(self, evidx);
591
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300592 if (self->curr_hot) {
Arnaldo Carvalho de Melob0ffb2c2012-04-03 15:32:45 -0300593 annotate_browser__set_rb_top(self, self->curr_hot);
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300594 self->b.navkeypressed = false;
595 }
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300596
597 nd = self->curr_hot;
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300598
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300599 while (1) {
Arnaldo Carvalho de Melo3af6e332011-10-13 08:52:46 -0300600 key = ui_browser__run(&self->b, delay_secs);
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300601
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300602 if (delay_secs != 0) {
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300603 annotate_browser__calc_percent(self, evidx);
604 /*
605 * Current line focus got out of the list of most active
606 * lines, NULL it so that if TAB|UNTAB is pressed, we
607 * move to curr_hot (current hottest line).
608 */
609 if (nd != NULL && RB_EMPTY_NODE(nd))
610 nd = NULL;
611 }
612
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300613 switch (key) {
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200614 case K_TIMER:
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300615 if (timer != NULL)
616 timer(arg);
617
618 if (delay_secs != 0)
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300619 symbol__annotate_decay_histogram(sym, evidx);
620 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200621 case K_TAB:
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300622 if (nd != NULL) {
623 nd = rb_prev(nd);
624 if (nd == NULL)
625 nd = rb_last(&self->entries);
626 } else
627 nd = self->curr_hot;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300628 break;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200629 case K_UNTAB:
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300630 if (nd != NULL)
631 nd = rb_next(nd);
632 if (nd == NULL)
633 nd = rb_first(&self->entries);
634 else
635 nd = self->curr_hot;
636 break;
Arnaldo Carvalho de Melo54e7a4e2012-05-12 16:36:55 -0300637 case K_F1:
Namhyung Kimef7c5372012-02-23 17:46:21 +0900638 case 'h':
Arnaldo Carvalho de Melo54e7a4e2012-05-12 16:36:55 -0300639 ui_browser__help_window(&self->b,
640 "UP/DOWN/PGUP\n"
641 "PGDN/SPACE Navigate\n"
642 "q/ESC/CTRL+C Exit\n\n"
643 "-> Go to target\n"
644 "<- Exit\n"
645 "h Cycle thru hottest instructions\n"
646 "j Toggle showing jump to target arrows\n"
647 "J Toggle showing number of jump sources on targets\n"
648 "n Search next string\n"
649 "o Toggle disassembler output/simplified view\n"
650 "s Toggle source code view\n"
651 "/ Search string\n"
652 "? Search previous string\n");
653 continue;
654 case 'H':
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300655 nd = self->curr_hot;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300656 break;
Namhyung Kimef7c5372012-02-23 17:46:21 +0900657 case 's':
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300658 if (annotate_browser__toggle_source(self))
659 ui_helpline__puts(help);
660 continue;
Arnaldo Carvalho de Meloe235f3f2012-04-02 13:21:55 -0300661 case 'o':
662 self->use_offset = !self->use_offset;
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300663 if (self->use_offset)
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300664 self->target_width = self->min_addr_width;
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300665 else
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300666 self->target_width = self->max_addr_width;
667update_addr_width:
668 self->addr_width = self->target_width;
669 if (self->show_nr_jumps)
670 self->addr_width += self->jumps_width + 1;
Arnaldo Carvalho de Meloe235f3f2012-04-02 13:21:55 -0300671 continue;
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300672 case 'j':
673 self->jump_arrows = !self->jump_arrows;
674 continue;
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300675 case 'J':
676 self->show_nr_jumps = !self->show_nr_jumps;
677 goto update_addr_width;
Arnaldo Carvalho de Melod3d1f612012-04-07 17:10:30 -0300678 case '/':
679 if (annotate_browser__search(self, delay_secs)) {
680show_help:
681 ui_helpline__puts(help);
682 }
683 continue;
684 case 'n':
685 if (self->searching_backwards ?
686 annotate_browser__continue_search_reverse(self, delay_secs) :
687 annotate_browser__continue_search(self, delay_secs))
688 goto show_help;
689 continue;
690 case '?':
691 if (annotate_browser__search_reverse(self, delay_secs))
692 goto show_help;
693 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200694 case K_ENTER:
695 case K_RIGHT:
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300696 if (self->selection == NULL)
Arnaldo Carvalho de Melo234a5372011-10-06 09:45:29 -0300697 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
Arnaldo Carvalho de Melo60521702012-04-02 13:58:33 -0300698 else if (self->selection->offset == -1)
Arnaldo Carvalho de Melo234a5372011-10-06 09:45:29 -0300699 ui_helpline__puts("Actions are only available for assembly lines.");
Arnaldo Carvalho de Meloc4cceae2012-04-20 15:57:15 -0300700 else if (!self->selection->ins) {
701 if (strcmp(self->selection->name, "retq"))
702 goto show_sup_ins;
703 goto out;
704 } else if (!(annotate_browser__jump(self) ||
705 annotate_browser__callq(self, evidx, timer, arg, delay_secs))) {
706show_sup_ins:
707 ui_helpline__puts("Actions are only available for 'callq', 'retq' & jump instructions.");
708 }
Arnaldo Carvalho de Melofe46e642011-10-19 13:18:13 -0200709 continue;
Arnaldo Carvalho de Melocf958002011-10-20 16:59:15 -0200710 case K_LEFT:
711 case K_ESC:
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -0300712 case 'q':
713 case CTRL('c'):
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300714 goto out;
Arnaldo Carvalho de Meloed7e5662011-10-13 08:31:22 -0300715 default:
716 continue;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300717 }
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300718
719 if (nd != NULL)
Arnaldo Carvalho de Melob0ffb2c2012-04-03 15:32:45 -0300720 annotate_browser__set_rb_top(self, nd);
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300721 }
722out:
Arnaldo Carvalho de Melo59e8fe32010-08-10 15:44:20 -0300723 ui_browser__hide(&self->b);
Arnaldo Carvalho de Melob50e0032010-08-11 10:07:43 -0300724 return key;
Arnaldo Carvalho de Melof1e92142010-08-10 15:14:53 -0300725}
726
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200727int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300728 void(*timer)(void *arg), void *arg, int delay_secs)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200729{
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200730 return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
Arnaldo Carvalho de Melo81cce8d2011-10-05 19:11:32 -0300731 timer, arg, delay_secs);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200732}
733
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300734static void annotate_browser__mark_jump_targets(struct annotate_browser *browser,
735 size_t size)
736{
737 u64 offset;
738
739 for (offset = 0; offset < size; ++offset) {
740 struct disasm_line *dl = browser->offsets[offset], *dlt;
741 struct browser_disasm_line *bdlt;
742
Arnaldo Carvalho de Melo38b31bd2012-04-25 14:18:42 -0300743 if (!dl || !dl->ins || !ins__is_jump(dl->ins) ||
744 !disasm_line__has_offset(dl))
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300745 continue;
746
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300747 if (dl->ops.target.offset >= size) {
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300748 ui__error("jump to after symbol!\n"
749 "size: %zx, jump target: %" PRIx64,
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300750 size, dl->ops.target.offset);
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300751 continue;
752 }
753
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300754 dlt = browser->offsets[dl->ops.target.offset];
Arnaldo Carvalho de Melo9481ede2012-04-25 07:48:42 -0300755 /*
756 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
757 * have to adjust to the previous offset?
758 */
759 if (dlt == NULL)
760 continue;
761
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300762 bdlt = disasm_line__browser(dlt);
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300763 if (++bdlt->jump_sources > browser->max_jump_sources)
764 browser->max_jump_sources = bdlt->jump_sources;
765
766 ++browser->nr_jumps;
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300767 }
768
769}
770
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300771static inline int width_jumps(int n)
772{
773 if (n >= 100)
774 return 5;
775 if (n / 10)
776 return 2;
777 return 1;
778}
779
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300780int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200781 void(*timer)(void *arg), void *arg,
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300782 int delay_secs)
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300783{
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300784 struct disasm_line *pos, *n;
Lin Mingdb9a9cbc2011-04-08 14:31:26 +0800785 struct annotation *notes;
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300786 const size_t size = symbol__size(sym);
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300787 struct map_symbol ms = {
788 .map = map,
789 .sym = sym,
790 };
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300791 struct annotate_browser browser = {
792 .b = {
Arnaldo Carvalho de Meloa3f895b2012-04-24 14:24:28 -0300793 .refresh = annotate_browser__refresh,
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300794 .seek = ui_browser__list_head_seek,
795 .write = annotate_browser__write,
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300796 .filter = disasm_line__filter,
Arnaldo Carvalho de Melo34958542011-10-05 19:35:54 -0300797 .priv = &ms,
Arnaldo Carvalho de Meloc172f742011-10-18 14:31:35 -0200798 .use_navkeypressed = true,
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300799 },
Arnaldo Carvalho de Melo8bf39cb2012-04-19 15:07:46 -0300800 .use_offset = true,
Arnaldo Carvalho de Melo9d1ef562012-04-27 16:35:29 -0300801 .jump_arrows = true,
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300802 };
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300803 int ret = -1;
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300804
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200805 if (sym == NULL)
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300806 return -1;
807
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200808 if (map->dso->annotate_warned)
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300809 return -1;
810
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300811 browser.offsets = zalloc(size * sizeof(struct disasm_line *));
812 if (browser.offsets == NULL) {
813 ui__error("Not enough memory!");
814 return -1;
815 }
816
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300817 if (symbol__annotate(sym, map, sizeof(struct browser_disasm_line)) < 0) {
Arnaldo Carvalho de Meloae557952011-10-26 08:00:55 -0200818 ui__error("%s", ui_helpline__last_msg);
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300819 goto out_free_offsets;
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300820 }
821
822 ui_helpline__push("Press <- or ESC to exit");
823
Lin Mingdb9a9cbc2011-04-08 14:31:26 +0800824 notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -0300825 browser.start = map__rip_2objdump(map, sym->start);
Lin Mingdb9a9cbc2011-04-08 14:31:26 +0800826
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -0200827 list_for_each_entry(pos, &notes->src->source, node) {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300828 struct browser_disasm_line *bpos;
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300829 size_t line_len = strlen(pos->line);
Arnaldo Carvalho de Meloc97cf422011-02-22 12:02:07 -0300830
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300831 if (browser.b.width < line_len)
832 browser.b.width = line_len;
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300833 bpos = disasm_line__browser(pos);
834 bpos->idx = browser.nr_entries++;
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300835 if (pos->offset != -1) {
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300836 bpos->idx_asm = browser.nr_asm_entries++;
Arnaldo Carvalho de Melo97148a92012-04-20 15:17:50 -0300837 /*
838 * FIXME: short term bandaid to cope with assembly
839 * routines that comes with labels in the same column
840 * as the address in objdump, sigh.
841 *
842 * E.g. copy_user_generic_unrolled
843 */
844 if (pos->offset < (s64)size)
845 browser.offsets[pos->offset] = pos;
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300846 } else
Arnaldo Carvalho de Melo887c0062012-04-19 10:29:53 -0300847 bpos->idx_asm = -1;
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300848 }
849
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300850 annotate_browser__mark_jump_targets(&browser, size);
851
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300852 browser.addr_width = browser.target_width = browser.min_addr_width = hex_width(size);
Arnaldo Carvalho de Melo83b1f2a2012-05-03 13:12:49 -0300853 browser.max_addr_width = hex_width(sym->end);
Arnaldo Carvalho de Melo2402e4a2012-05-12 16:21:53 -0300854 browser.jumps_width = width_jumps(browser.max_jump_sources);
Arnaldo Carvalho de Melo0361fc22011-10-14 12:31:21 -0300855 browser.b.nr_entries = browser.nr_entries;
Lin Mingdb9a9cbc2011-04-08 14:31:26 +0800856 browser.b.entries = &notes->src->source,
Arnaldo Carvalho de Melo92221162010-08-09 15:30:40 -0300857 browser.b.width += 18; /* Percentage */
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200858 ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -0200859 list_for_each_entry_safe(pos, n, &notes->src->source, node) {
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300860 list_del(&pos->node);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300861 disasm_line__free(pos);
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300862 }
Arnaldo Carvalho de Melob793a402012-04-19 12:19:22 -0300863
864out_free_offsets:
865 free(browser.offsets);
Arnaldo Carvalho de Melo211ef122010-08-10 14:54:09 -0300866 return ret;
867}