1 #include "../../util.h"
2 #include "../browser.h"
3 #include "../helpline.h"
4 #include "../libslang.h"
7 #include "../../annotate.h"
8 #include "../../hist.h"
9 #include "../../sort.h"
10 #include "../../symbol.h"
14 struct annotate_browser
{
16 struct rb_root entries
;
17 struct rb_node
*curr_hot
;
18 struct objdump_line
*selection
;
24 struct objdump_line_rb_node
{
25 struct rb_node rb_node
;
32 struct objdump_line_rb_node
*objdump_line__rb(struct objdump_line
*self
)
34 return (struct objdump_line_rb_node
*)(self
+ 1);
37 static bool objdump_line__filter(struct ui_browser
*browser
, void *entry
)
39 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
41 if (ab
->hide_src_code
) {
42 struct objdump_line
*ol
= list_entry(entry
, struct objdump_line
, node
);
43 return ol
->offset
== -1;
49 static void annotate_browser__write(struct ui_browser
*self
, void *entry
, int row
)
51 struct annotate_browser
*ab
= container_of(self
, struct annotate_browser
, b
);
52 struct objdump_line
*ol
= list_entry(entry
, struct objdump_line
, node
);
53 bool current_entry
= ui_browser__is_current_entry(self
, row
);
54 int width
= self
->width
;
56 if (ol
->offset
!= -1) {
57 struct objdump_line_rb_node
*olrb
= objdump_line__rb(ol
);
58 ui_browser__set_percent_color(self
, olrb
->percent
, current_entry
);
59 slsmg_printf(" %7.2f ", olrb
->percent
);
61 ui_browser__set_percent_color(self
, 0, current_entry
);
62 slsmg_write_nstring(" ", 9);
65 SLsmg_write_char(':');
66 slsmg_write_nstring(" ", 8);
68 /* The scroll bar isn't being used */
69 if (!self
->navkeypressed
)
73 slsmg_write_nstring(" ", width
- 18);
75 slsmg_write_nstring(ol
->line
, width
- 18);
78 ui_browser__set_color(self
, HE_COLORSET_CODE
);
83 static double objdump_line__calc_percent(struct objdump_line
*self
,
84 struct symbol
*sym
, int evidx
)
88 if (self
->offset
!= -1) {
89 int len
= sym
->end
- sym
->start
;
90 unsigned int hits
= 0;
91 struct annotation
*notes
= symbol__annotation(sym
);
92 struct source_line
*src_line
= notes
->src
->lines
;
93 struct sym_hist
*h
= annotation__histogram(notes
, evidx
);
94 s64 offset
= self
->offset
;
95 struct objdump_line
*next
;
97 next
= objdump__get_next_ip_line(¬es
->src
->source
, self
);
98 while (offset
< (s64
)len
&&
99 (next
== NULL
|| offset
< next
->offset
)) {
101 percent
+= src_line
[offset
].percent
;
103 hits
+= h
->addr
[offset
];
108 * If the percentage wasn't already calculated in
109 * symbol__get_source_line, do it now:
111 if (src_line
== NULL
&& h
->sum
)
112 percent
= 100.0 * hits
/ h
->sum
;
118 static void objdump__insert_line(struct rb_root
*self
,
119 struct objdump_line_rb_node
*line
)
121 struct rb_node
**p
= &self
->rb_node
;
122 struct rb_node
*parent
= NULL
;
123 struct objdump_line_rb_node
*l
;
127 l
= rb_entry(parent
, struct objdump_line_rb_node
, rb_node
);
128 if (line
->percent
< l
->percent
)
133 rb_link_node(&line
->rb_node
, parent
, p
);
134 rb_insert_color(&line
->rb_node
, self
);
137 static void annotate_browser__set_top(struct annotate_browser
*self
,
140 struct objdump_line_rb_node
*rbpos
;
141 struct objdump_line
*pos
;
144 ui_browser__refresh_dimensions(&self
->b
);
145 back
= self
->b
.height
/ 2;
146 rbpos
= rb_entry(nd
, struct objdump_line_rb_node
, rb_node
);
147 pos
= ((struct objdump_line
*)rbpos
) - 1;
148 self
->b
.top_idx
= self
->b
.index
= rbpos
->idx
;
150 while (self
->b
.top_idx
!= 0 && back
!= 0) {
151 pos
= list_entry(pos
->node
.prev
, struct objdump_line
, node
);
161 static void annotate_browser__calc_percent(struct annotate_browser
*browser
,
164 struct map_symbol
*ms
= browser
->b
.priv
;
165 struct symbol
*sym
= ms
->sym
;
166 struct annotation
*notes
= symbol__annotation(sym
);
167 struct objdump_line
*pos
;
169 browser
->entries
= RB_ROOT
;
171 pthread_mutex_lock(¬es
->lock
);
173 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
174 struct objdump_line_rb_node
*rbpos
= objdump_line__rb(pos
);
175 rbpos
->percent
= objdump_line__calc_percent(pos
, sym
, evidx
);
176 if (rbpos
->percent
< 0.01) {
177 RB_CLEAR_NODE(&rbpos
->rb_node
);
180 objdump__insert_line(&browser
->entries
, rbpos
);
182 pthread_mutex_unlock(¬es
->lock
);
184 browser
->curr_hot
= rb_last(&browser
->entries
);
187 static bool annotate_browser__toggle_source(struct annotate_browser
*browser
)
189 struct objdump_line
*ol
;
190 struct objdump_line_rb_node
*olrb
;
191 off_t offset
= browser
->b
.index
- browser
->b
.top_idx
;
193 browser
->b
.seek(&browser
->b
, offset
, SEEK_CUR
);
194 ol
= list_entry(browser
->b
.top
, struct objdump_line
, node
);
195 olrb
= objdump_line__rb(ol
);
197 if (browser
->hide_src_code
) {
198 if (olrb
->idx_asm
< offset
)
201 browser
->b
.nr_entries
= browser
->nr_entries
;
202 browser
->hide_src_code
= false;
203 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
204 browser
->b
.top_idx
= olrb
->idx
- offset
;
205 browser
->b
.index
= olrb
->idx
;
207 if (olrb
->idx_asm
< 0) {
208 ui_helpline__puts("Only available for assembly lines.");
209 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
213 if (olrb
->idx_asm
< offset
)
214 offset
= olrb
->idx_asm
;
216 browser
->b
.nr_entries
= browser
->nr_asm_entries
;
217 browser
->hide_src_code
= true;
218 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
219 browser
->b
.top_idx
= olrb
->idx_asm
- offset
;
220 browser
->b
.index
= olrb
->idx_asm
;
226 static int annotate_browser__run(struct annotate_browser
*self
, int evidx
,
227 void(*timer
)(void *arg
),
228 void *arg
, int delay_secs
)
230 struct rb_node
*nd
= NULL
;
231 struct map_symbol
*ms
= self
->b
.priv
;
232 struct symbol
*sym
= ms
->sym
;
233 const char *help
= "<-, ESC: exit, TAB/shift+TAB: cycle hottest lines, "
234 "H: Hottest, -> Line action, S -> Toggle source "
238 if (ui_browser__show(&self
->b
, sym
->name
, help
) < 0)
241 annotate_browser__calc_percent(self
, evidx
);
244 annotate_browser__set_top(self
, self
->curr_hot
);
249 key
= ui_browser__run(&self
->b
, delay_secs
);
251 if (delay_secs
!= 0) {
252 annotate_browser__calc_percent(self
, evidx
);
254 * Current line focus got out of the list of most active
255 * lines, NULL it so that if TAB|UNTAB is pressed, we
256 * move to curr_hot (current hottest line).
258 if (nd
!= NULL
&& RB_EMPTY_NODE(nd
))
268 symbol__annotate_decay_histogram(sym
, evidx
);
274 nd
= rb_last(&self
->entries
);
282 nd
= rb_first(&self
->entries
);
290 if (annotate_browser__toggle_source(self
))
291 ui_helpline__puts(help
);
295 if (self
->selection
== NULL
) {
296 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
300 if (self
->selection
->offset
== -1) {
301 ui_helpline__puts("Actions are only available for assembly lines.");
304 char *s
= strstr(self
->selection
->line
, "callq ");
305 struct annotation
*notes
;
306 struct symbol
*target
;
310 ui_helpline__puts("Actions are only available for the 'callq' instruction.");
316 ui_helpline__puts("Invallid callq instruction.");
320 ip
= strtoull(s
, NULL
, 16);
321 ip
= ms
->map
->map_ip(ms
->map
, ip
);
322 target
= map__find_symbol(ms
->map
, ip
, NULL
);
323 if (target
== NULL
) {
324 ui_helpline__puts("The called function was not found.");
328 notes
= symbol__annotation(target
);
329 pthread_mutex_lock(¬es
->lock
);
331 if (notes
->src
== NULL
&& symbol__alloc_hist(target
) < 0) {
332 pthread_mutex_unlock(¬es
->lock
);
333 ui__warning("Not enough memory for annotating '%s' symbol!\n",
338 pthread_mutex_unlock(¬es
->lock
);
339 symbol__tui_annotate(target
, ms
->map
, evidx
,
340 timer
, arg
, delay_secs
);
353 annotate_browser__set_top(self
, nd
);
356 ui_browser__hide(&self
->b
);
360 int hist_entry__tui_annotate(struct hist_entry
*he
, int evidx
,
361 void(*timer
)(void *arg
), void *arg
, int delay_secs
)
363 return symbol__tui_annotate(he
->ms
.sym
, he
->ms
.map
, evidx
,
364 timer
, arg
, delay_secs
);
367 int symbol__tui_annotate(struct symbol
*sym
, struct map
*map
, int evidx
,
368 void(*timer
)(void *arg
), void *arg
,
371 struct objdump_line
*pos
, *n
;
372 struct annotation
*notes
;
373 struct map_symbol ms
= {
377 struct annotate_browser browser
= {
379 .refresh
= ui_browser__list_head_refresh
,
380 .seek
= ui_browser__list_head_seek
,
381 .write
= annotate_browser__write
,
382 .filter
= objdump_line__filter
,
384 .use_navkeypressed
= true,
392 if (map
->dso
->annotate_warned
)
395 if (symbol__annotate(sym
, map
, sizeof(struct objdump_line_rb_node
)) < 0) {
396 ui__error("%s", ui_helpline__last_msg
);
400 ui_helpline__push("Press <- or ESC to exit");
402 notes
= symbol__annotation(sym
);
404 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
405 struct objdump_line_rb_node
*rbpos
;
406 size_t line_len
= strlen(pos
->line
);
408 if (browser
.b
.width
< line_len
)
409 browser
.b
.width
= line_len
;
410 rbpos
= objdump_line__rb(pos
);
411 rbpos
->idx
= browser
.nr_entries
++;
412 if (pos
->offset
!= -1)
413 rbpos
->idx_asm
= browser
.nr_asm_entries
++;
418 browser
.b
.nr_entries
= browser
.nr_entries
;
419 browser
.b
.entries
= ¬es
->src
->source
,
420 browser
.b
.width
+= 18; /* Percentage */
421 ret
= annotate_browser__run(&browser
, evidx
, timer
, arg
, delay_secs
);
422 list_for_each_entry_safe(pos
, n
, ¬es
->src
->source
, node
) {
423 list_del(&pos
->node
);
424 objdump_line__free(pos
);