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
;
26 struct objdump_line_rb_node
{
27 struct rb_node rb_node
;
34 struct objdump_line_rb_node
*objdump_line__rb(struct objdump_line
*self
)
36 return (struct objdump_line_rb_node
*)(self
+ 1);
39 static bool objdump_line__filter(struct ui_browser
*browser
, void *entry
)
41 struct annotate_browser
*ab
= container_of(browser
, struct annotate_browser
, b
);
43 if (ab
->hide_src_code
) {
44 struct objdump_line
*ol
= list_entry(entry
, struct objdump_line
, node
);
45 return ol
->offset
== -1;
51 static void annotate_browser__write(struct ui_browser
*self
, void *entry
, int row
)
53 struct annotate_browser
*ab
= container_of(self
, struct annotate_browser
, b
);
54 struct objdump_line
*ol
= list_entry(entry
, struct objdump_line
, node
);
55 bool current_entry
= ui_browser__is_current_entry(self
, row
);
56 bool change_color
= (!ab
->hide_src_code
&&
57 (!current_entry
|| (self
->use_navkeypressed
&&
58 !self
->navkeypressed
)));
59 int width
= self
->width
;
61 if (ol
->offset
!= -1) {
62 struct objdump_line_rb_node
*olrb
= objdump_line__rb(ol
);
63 ui_browser__set_percent_color(self
, olrb
->percent
, current_entry
);
64 slsmg_printf(" %7.2f ", olrb
->percent
);
66 ui_browser__set_percent_color(self
, 0, current_entry
);
67 slsmg_write_nstring(" ", 9);
70 SLsmg_write_char(':');
71 slsmg_write_nstring(" ", 8);
73 /* The scroll bar isn't being used */
74 if (!self
->navkeypressed
)
77 if (ol
->offset
!= -1 && change_color
)
78 ui_browser__set_color(self
, HE_COLORSET_CODE
);
81 slsmg_write_nstring(" ", width
- 18);
82 else if (ol
->offset
== -1)
83 slsmg_write_nstring(ol
->line
, width
- 18);
86 u64 addr
= ol
->offset
;
87 int printed
, color
= -1;
92 printed
= scnprintf(bf
, sizeof(bf
), " %" PRIx64
":", addr
);
94 color
= ui_browser__set_color(self
, HE_COLORSET_ADDR
);
95 slsmg_write_nstring(bf
, printed
);
97 ui_browser__set_color(self
, color
);
98 slsmg_write_nstring(ol
->line
, width
- 18 - printed
);
105 static double objdump_line__calc_percent(struct objdump_line
*self
,
106 struct symbol
*sym
, int evidx
)
108 double percent
= 0.0;
110 if (self
->offset
!= -1) {
111 int len
= sym
->end
- sym
->start
;
112 unsigned int hits
= 0;
113 struct annotation
*notes
= symbol__annotation(sym
);
114 struct source_line
*src_line
= notes
->src
->lines
;
115 struct sym_hist
*h
= annotation__histogram(notes
, evidx
);
116 s64 offset
= self
->offset
;
117 struct objdump_line
*next
;
119 next
= objdump__get_next_ip_line(¬es
->src
->source
, self
);
120 while (offset
< (s64
)len
&&
121 (next
== NULL
|| offset
< next
->offset
)) {
123 percent
+= src_line
[offset
].percent
;
125 hits
+= h
->addr
[offset
];
130 * If the percentage wasn't already calculated in
131 * symbol__get_source_line, do it now:
133 if (src_line
== NULL
&& h
->sum
)
134 percent
= 100.0 * hits
/ h
->sum
;
140 static void objdump__insert_line(struct rb_root
*self
,
141 struct objdump_line_rb_node
*line
)
143 struct rb_node
**p
= &self
->rb_node
;
144 struct rb_node
*parent
= NULL
;
145 struct objdump_line_rb_node
*l
;
149 l
= rb_entry(parent
, struct objdump_line_rb_node
, rb_node
);
150 if (line
->percent
< l
->percent
)
155 rb_link_node(&line
->rb_node
, parent
, p
);
156 rb_insert_color(&line
->rb_node
, self
);
159 static void annotate_browser__set_top(struct annotate_browser
*self
,
160 struct objdump_line
*pos
, u32 idx
)
164 ui_browser__refresh_dimensions(&self
->b
);
165 back
= self
->b
.height
/ 2;
166 self
->b
.top_idx
= self
->b
.index
= idx
;
168 while (self
->b
.top_idx
!= 0 && back
!= 0) {
169 pos
= list_entry(pos
->node
.prev
, struct objdump_line
, node
);
178 static void annotate_browser__set_rb_top(struct annotate_browser
*browser
,
181 struct objdump_line_rb_node
*rbpos
;
182 struct objdump_line
*pos
;
184 rbpos
= rb_entry(nd
, struct objdump_line_rb_node
, rb_node
);
185 pos
= ((struct objdump_line
*)rbpos
) - 1;
186 annotate_browser__set_top(browser
, pos
, rbpos
->idx
);
187 browser
->curr_hot
= nd
;
190 static void annotate_browser__calc_percent(struct annotate_browser
*browser
,
193 struct map_symbol
*ms
= browser
->b
.priv
;
194 struct symbol
*sym
= ms
->sym
;
195 struct annotation
*notes
= symbol__annotation(sym
);
196 struct objdump_line
*pos
;
198 browser
->entries
= RB_ROOT
;
200 pthread_mutex_lock(¬es
->lock
);
202 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
203 struct objdump_line_rb_node
*rbpos
= objdump_line__rb(pos
);
204 rbpos
->percent
= objdump_line__calc_percent(pos
, sym
, evidx
);
205 if (rbpos
->percent
< 0.01) {
206 RB_CLEAR_NODE(&rbpos
->rb_node
);
209 objdump__insert_line(&browser
->entries
, rbpos
);
211 pthread_mutex_unlock(¬es
->lock
);
213 browser
->curr_hot
= rb_last(&browser
->entries
);
216 static bool annotate_browser__toggle_source(struct annotate_browser
*browser
)
218 struct objdump_line
*ol
;
219 struct objdump_line_rb_node
*olrb
;
220 off_t offset
= browser
->b
.index
- browser
->b
.top_idx
;
222 browser
->b
.seek(&browser
->b
, offset
, SEEK_CUR
);
223 ol
= list_entry(browser
->b
.top
, struct objdump_line
, node
);
224 olrb
= objdump_line__rb(ol
);
226 if (browser
->hide_src_code
) {
227 if (olrb
->idx_asm
< offset
)
230 browser
->b
.nr_entries
= browser
->nr_entries
;
231 browser
->hide_src_code
= false;
232 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
233 browser
->b
.top_idx
= olrb
->idx
- offset
;
234 browser
->b
.index
= olrb
->idx
;
236 if (olrb
->idx_asm
< 0) {
237 ui_helpline__puts("Only available for assembly lines.");
238 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
242 if (olrb
->idx_asm
< offset
)
243 offset
= olrb
->idx_asm
;
245 browser
->b
.nr_entries
= browser
->nr_asm_entries
;
246 browser
->hide_src_code
= true;
247 browser
->b
.seek(&browser
->b
, -offset
, SEEK_CUR
);
248 browser
->b
.top_idx
= olrb
->idx_asm
- offset
;
249 browser
->b
.index
= olrb
->idx_asm
;
255 static bool annotate_browser__callq(struct annotate_browser
*browser
,
256 int evidx
, void (*timer
)(void *arg
),
257 void *arg
, int delay_secs
)
259 struct map_symbol
*ms
= browser
->b
.priv
;
260 struct symbol
*sym
= ms
->sym
;
261 struct annotation
*notes
;
262 struct symbol
*target
;
263 char *s
= strstr(browser
->selection
->line
, "callq ");
271 ui_helpline__puts("Invallid callq instruction.");
275 ip
= strtoull(s
, NULL
, 16);
276 ip
= ms
->map
->map_ip(ms
->map
, ip
);
277 target
= map__find_symbol(ms
->map
, ip
, NULL
);
278 if (target
== NULL
) {
279 ui_helpline__puts("The called function was not found.");
283 notes
= symbol__annotation(target
);
284 pthread_mutex_lock(¬es
->lock
);
286 if (notes
->src
== NULL
&& symbol__alloc_hist(target
) < 0) {
287 pthread_mutex_unlock(¬es
->lock
);
288 ui__warning("Not enough memory for annotating '%s' symbol!\n",
293 pthread_mutex_unlock(¬es
->lock
);
294 symbol__tui_annotate(target
, ms
->map
, evidx
, timer
, arg
, delay_secs
);
295 ui_browser__show_title(&browser
->b
, sym
->name
);
299 static int annotate_browser__run(struct annotate_browser
*self
, int evidx
,
300 void(*timer
)(void *arg
),
301 void *arg
, int delay_secs
)
303 struct rb_node
*nd
= NULL
;
304 struct map_symbol
*ms
= self
->b
.priv
;
305 struct symbol
*sym
= ms
->sym
;
306 const char *help
= "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, "
307 "H: Go to hottest line, ->/ENTER: Line action, "
308 "O: Toggle offset view, "
309 "S: Toggle source code view";
312 if (ui_browser__show(&self
->b
, sym
->name
, help
) < 0)
315 annotate_browser__calc_percent(self
, evidx
);
318 annotate_browser__set_rb_top(self
, self
->curr_hot
);
323 key
= ui_browser__run(&self
->b
, delay_secs
);
325 if (delay_secs
!= 0) {
326 annotate_browser__calc_percent(self
, evidx
);
328 * Current line focus got out of the list of most active
329 * lines, NULL it so that if TAB|UNTAB is pressed, we
330 * move to curr_hot (current hottest line).
332 if (nd
!= NULL
&& RB_EMPTY_NODE(nd
))
342 symbol__annotate_decay_histogram(sym
, evidx
);
348 nd
= rb_last(&self
->entries
);
356 nd
= rb_first(&self
->entries
);
366 if (annotate_browser__toggle_source(self
))
367 ui_helpline__puts(help
);
371 self
->use_offset
= !self
->use_offset
;
375 if (self
->selection
== NULL
)
376 ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
377 else if (self
->selection
->offset
== -1)
378 ui_helpline__puts("Actions are only available for assembly lines.");
379 else if (!annotate_browser__callq(self
, evidx
, timer
, arg
, delay_secs
))
380 ui_helpline__puts("Actions are only available for the 'callq' instruction.");
392 annotate_browser__set_rb_top(self
, nd
);
395 ui_browser__hide(&self
->b
);
399 int hist_entry__tui_annotate(struct hist_entry
*he
, int evidx
,
400 void(*timer
)(void *arg
), void *arg
, int delay_secs
)
402 return symbol__tui_annotate(he
->ms
.sym
, he
->ms
.map
, evidx
,
403 timer
, arg
, delay_secs
);
406 int symbol__tui_annotate(struct symbol
*sym
, struct map
*map
, int evidx
,
407 void(*timer
)(void *arg
), void *arg
,
410 struct objdump_line
*pos
, *n
;
411 struct annotation
*notes
;
412 struct map_symbol ms
= {
416 struct annotate_browser browser
= {
418 .refresh
= ui_browser__list_head_refresh
,
419 .seek
= ui_browser__list_head_seek
,
420 .write
= annotate_browser__write
,
421 .filter
= objdump_line__filter
,
423 .use_navkeypressed
= true,
431 if (map
->dso
->annotate_warned
)
434 if (symbol__annotate(sym
, map
, sizeof(struct objdump_line_rb_node
)) < 0) {
435 ui__error("%s", ui_helpline__last_msg
);
439 ui_helpline__push("Press <- or ESC to exit");
441 notes
= symbol__annotation(sym
);
442 browser
.start
= map__rip_2objdump(map
, sym
->start
);
444 list_for_each_entry(pos
, ¬es
->src
->source
, node
) {
445 struct objdump_line_rb_node
*rbpos
;
446 size_t line_len
= strlen(pos
->line
);
448 if (browser
.b
.width
< line_len
)
449 browser
.b
.width
= line_len
;
450 rbpos
= objdump_line__rb(pos
);
451 rbpos
->idx
= browser
.nr_entries
++;
452 if (pos
->offset
!= -1)
453 rbpos
->idx_asm
= browser
.nr_asm_entries
++;
458 browser
.b
.nr_entries
= browser
.nr_entries
;
459 browser
.b
.entries
= ¬es
->src
->source
,
460 browser
.b
.width
+= 18; /* Percentage */
461 ret
= annotate_browser__run(&browser
, evidx
, timer
, arg
, delay_secs
);
462 list_for_each_entry_safe(pos
, n
, ¬es
->src
->source
, node
) {
463 list_del(&pos
->node
);
464 objdump_line__free(pos
);