xref: /linux/tools/perf/ui/browsers/annotate.c (revision 9e906a9dead17d81d6c2687f65e159231d0e3286)
1 // SPDX-License-Identifier: GPL-2.0
2 #include "../browser.h"
3 #include "../helpline.h"
4 #include "../ui.h"
5 #include "../../util/annotate.h"
6 #include "../../util/debug.h"
7 #include "../../util/debuginfo.h"
8 #include "../../util/dso.h"
9 #include "../../util/hashmap.h"
10 #include "../../util/hist.h"
11 #include "../../util/sort.h"
12 #include "../../util/map.h"
13 #include "../../util/mutex.h"
14 #include "../../util/symbol.h"
15 #include "../../util/evsel.h"
16 #include "../../util/evlist.h"
17 #include "../../util/thread.h"
18 #include <inttypes.h>
19 #include <linux/err.h>
20 #include <linux/kernel.h>
21 #include <linux/string.h>
22 #include <linux/zalloc.h>
23 #include <sys/ttydefaults.h>
24 #include <asm/bug.h>
25 
26 struct arch;
27 
28 struct annotate_browser {
29 	struct ui_browser	    b;
30 	struct rb_root		    entries;
31 	struct rb_node		   *curr_hot;
32 	struct annotation_line	   *selection;
33 	struct arch		   *arch;
34 	/*
35 	 * perf top can delete hist_entry anytime.  Callers should make sure
36 	 * its lifetime.
37 	 */
38 	struct hist_entry	   *he;
39 	struct debuginfo	   *dbg;
40 	struct evsel		   *evsel;
41 	struct hashmap		   *type_hash;
42 	bool			    searching_backwards;
43 	char			    search_bf[128];
44 };
45 
46 /* A copy of target hist_entry for perf top. */
47 static struct hist_entry annotate_he;
48 
type_hash(long key,void * ctx __maybe_unused)49 static size_t type_hash(long key, void *ctx __maybe_unused)
50 {
51 	return key;
52 }
53 
type_equal(long key1,long key2,void * ctx __maybe_unused)54 static bool type_equal(long key1, long key2, void *ctx __maybe_unused)
55 {
56 	return key1 == key2;
57 }
58 
browser__annotation(struct ui_browser * browser)59 static inline struct annotation *browser__annotation(struct ui_browser *browser)
60 {
61 	struct map_symbol *ms = browser->priv;
62 	return symbol__annotation(ms->sym);
63 }
64 
disasm_line__filter(struct ui_browser * browser __maybe_unused,void * entry)65 static bool disasm_line__filter(struct ui_browser *browser __maybe_unused, void *entry)
66 {
67 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
68 	return annotation_line__filter(al);
69 }
70 
ui_browser__jumps_percent_color(struct ui_browser * browser,int nr,bool current)71 static int ui_browser__jumps_percent_color(struct ui_browser *browser, int nr, bool current)
72 {
73 	struct annotation *notes = browser__annotation(browser);
74 
75 	if (current && (!browser->use_navkeypressed || browser->navkeypressed))
76 		return HE_COLORSET_SELECTED;
77 	if (nr == notes->src->max_jump_sources)
78 		return HE_COLORSET_TOP;
79 	if (nr > 1)
80 		return HE_COLORSET_MEDIUM;
81 	return HE_COLORSET_NORMAL;
82 }
83 
ui_browser__set_jumps_percent_color(void * browser,int nr,bool current)84 static int ui_browser__set_jumps_percent_color(void *browser, int nr, bool current)
85 {
86 	 int color = ui_browser__jumps_percent_color(browser, nr, current);
87 	 return ui_browser__set_color(browser, color);
88 }
89 
annotate_browser__set_color(void * browser,int color)90 static int annotate_browser__set_color(void *browser, int color)
91 {
92 	return ui_browser__set_color(browser, color);
93 }
94 
annotate_browser__write_graph(void * browser,int graph)95 static void annotate_browser__write_graph(void *browser, int graph)
96 {
97 	ui_browser__write_graph(browser, graph);
98 }
99 
annotate_browser__set_percent_color(void * browser,double percent,bool current)100 static void annotate_browser__set_percent_color(void *browser, double percent, bool current)
101 {
102 	ui_browser__set_percent_color(browser, percent, current);
103 }
104 
annotate_browser__printf(void * browser,const char * fmt,...)105 static void annotate_browser__printf(void *browser, const char *fmt, ...)
106 {
107 	va_list args;
108 
109 	va_start(args, fmt);
110 	ui_browser__vprintf(browser, fmt, args);
111 	va_end(args);
112 }
113 
annotate_browser__write(struct ui_browser * browser,void * entry,int row)114 static void annotate_browser__write(struct ui_browser *browser, void *entry, int row)
115 {
116 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
117 	struct annotation *notes = browser__annotation(browser);
118 	struct annotation_line *al = list_entry(entry, struct annotation_line, node);
119 	const bool is_current_entry = ui_browser__is_current_entry(browser, row);
120 	struct annotation_write_ops ops = {
121 		.first_line		 = row == 0,
122 		.current_entry		 = is_current_entry,
123 		.change_color		 = (!annotate_opts.hide_src_code &&
124 					    (!is_current_entry ||
125 					     (browser->use_navkeypressed &&
126 					      !browser->navkeypressed))),
127 		.width			 = browser->width,
128 		.obj			 = browser,
129 		.set_color		 = annotate_browser__set_color,
130 		.set_percent_color	 = annotate_browser__set_percent_color,
131 		.set_jumps_percent_color = ui_browser__set_jumps_percent_color,
132 		.printf			 = annotate_browser__printf,
133 		.write_graph		 = annotate_browser__write_graph,
134 	};
135 	struct annotation_print_data apd = {
136 		.he = ab->he,
137 		.arch = ab->arch,
138 		.evsel = ab->evsel,
139 		.dbg = ab->dbg,
140 	};
141 
142 	/* The scroll bar isn't being used */
143 	if (!browser->navkeypressed)
144 		ops.width += 1;
145 
146 	if (!IS_ERR_OR_NULL(ab->type_hash))
147 		apd.type_hash = ab->type_hash;
148 
149 	annotation_line__write(al, notes, &ops, &apd);
150 
151 	if (ops.current_entry)
152 		ab->selection = al;
153 }
154 
is_fused(struct annotate_browser * ab,struct disasm_line * cursor)155 static int is_fused(struct annotate_browser *ab, struct disasm_line *cursor)
156 {
157 	struct disasm_line *pos = list_prev_entry(cursor, al.node);
158 	const char *name;
159 	int diff = 1;
160 
161 	while (pos && pos->al.offset == -1) {
162 		pos = list_prev_entry(pos, al.node);
163 		if (!annotate_opts.hide_src_code)
164 			diff++;
165 	}
166 
167 	if (!pos)
168 		return 0;
169 
170 	if (ins__is_lock(&pos->ins))
171 		name = pos->ops.locked.ins.name;
172 	else
173 		name = pos->ins.name;
174 
175 	if (!name || !cursor->ins.name)
176 		return 0;
177 
178 	if (ins__is_fused(ab->arch, name, cursor->ins.name))
179 		return diff;
180 	return 0;
181 }
182 
annotate_browser__draw_current_jump(struct ui_browser * browser)183 static void annotate_browser__draw_current_jump(struct ui_browser *browser)
184 {
185 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
186 	struct disasm_line *cursor = disasm_line(ab->selection);
187 	struct annotation_line *target;
188 	unsigned int from, to;
189 	struct map_symbol *ms = ab->b.priv;
190 	struct symbol *sym = ms->sym;
191 	struct annotation *notes = symbol__annotation(sym);
192 	u8 pcnt_width = annotation__pcnt_width(notes);
193 	u8 cntr_width = annotation__br_cntr_width();
194 	int width;
195 	int diff = 0;
196 
197 	/* PLT symbols contain external offsets */
198 	if (strstr(sym->name, "@plt"))
199 		return;
200 
201 	if (!disasm_line__is_valid_local_jump(cursor, sym))
202 		return;
203 
204 	/*
205 	 * This first was seen with a gcc function, _cpp_lex_token, that
206 	 * has the usual jumps:
207 	 *
208 	 *  │1159e6c: ↓ jne    115aa32 <_cpp_lex_token@@Base+0xf92>
209 	 *
210 	 * I.e. jumps to a label inside that function (_cpp_lex_token), and
211 	 * those works, but also this kind:
212 	 *
213 	 *  │1159e8b: ↓ jne    c469be <cpp_named_operator2name@@Base+0xa72>
214 	 *
215 	 *  I.e. jumps to another function, outside _cpp_lex_token, which
216 	 *  are not being correctly handled generating as a side effect references
217 	 *  to ab->offset[] entries that are set to NULL, so to make this code
218 	 *  more robust, check that here.
219 	 *
220 	 *  A proper fix for will be put in place, looking at the function
221 	 *  name right after the '<' token and probably treating this like a
222 	 *  'call' instruction.
223 	 */
224 	target = annotated_source__get_line(notes->src, cursor->ops.target.offset);
225 	if (target == NULL) {
226 		ui_helpline__printf("WARN: jump target inconsistency, press 'o', notes->offsets[%#x] = NULL\n",
227 				    cursor->ops.target.offset);
228 		return;
229 	}
230 
231 	if (annotate_opts.hide_src_code) {
232 		from = cursor->al.idx_asm;
233 		to = target->idx_asm;
234 	} else {
235 		from = (u64)cursor->al.idx;
236 		to = (u64)target->idx;
237 	}
238 
239 	width = annotation__cycles_width(notes);
240 
241 	ui_browser__set_color(browser, HE_COLORSET_JUMP_ARROWS);
242 	__ui_browser__line_arrow(browser,
243 				 pcnt_width + 2 + notes->src->widths.addr + width + cntr_width,
244 				 from, to);
245 
246 	diff = is_fused(ab, cursor);
247 	if (diff > 0) {
248 		ui_browser__mark_fused(browser,
249 				       pcnt_width + 3 + notes->src->widths.addr + width + cntr_width,
250 				       from - diff, diff, to > from);
251 	}
252 }
253 
annotate_browser__refresh(struct ui_browser * browser)254 static unsigned int annotate_browser__refresh(struct ui_browser *browser)
255 {
256 	struct annotation *notes = browser__annotation(browser);
257 	int ret = ui_browser__list_head_refresh(browser);
258 	int pcnt_width = annotation__pcnt_width(notes);
259 
260 	if (annotate_opts.jump_arrows)
261 		annotate_browser__draw_current_jump(browser);
262 
263 	ui_browser__set_color(browser, HE_COLORSET_NORMAL);
264 	__ui_browser__vline(browser, pcnt_width, 0, browser->rows - 1);
265 	return ret;
266 }
267 
disasm__cmp(struct annotation_line * a,struct annotation_line * b,int percent_type)268 static double disasm__cmp(struct annotation_line *a, struct annotation_line *b,
269 						  int percent_type)
270 {
271 	int i;
272 
273 	for (i = 0; i < a->data_nr; i++) {
274 		if (a->data[i].percent[percent_type] == b->data[i].percent[percent_type])
275 			continue;
276 		return a->data[i].percent[percent_type] -
277 			   b->data[i].percent[percent_type];
278 	}
279 	return 0;
280 }
281 
disasm_rb_tree__insert(struct annotate_browser * browser,struct annotation_line * al)282 static void disasm_rb_tree__insert(struct annotate_browser *browser,
283 				struct annotation_line *al)
284 {
285 	struct rb_root *root = &browser->entries;
286 	struct rb_node **p = &root->rb_node;
287 	struct rb_node *parent = NULL;
288 	struct annotation_line *l;
289 
290 	while (*p != NULL) {
291 		parent = *p;
292 		l = rb_entry(parent, struct annotation_line, rb_node);
293 
294 		if (disasm__cmp(al, l, annotate_opts.percent_type) < 0)
295 			p = &(*p)->rb_left;
296 		else
297 			p = &(*p)->rb_right;
298 	}
299 	rb_link_node(&al->rb_node, parent, p);
300 	rb_insert_color(&al->rb_node, root);
301 }
302 
annotate_browser__set_top(struct annotate_browser * browser,struct annotation_line * pos,u32 idx)303 static void annotate_browser__set_top(struct annotate_browser *browser,
304 				      struct annotation_line *pos, u32 idx)
305 {
306 	unsigned back;
307 
308 	ui_browser__refresh_dimensions(&browser->b);
309 	back = browser->b.height / 2;
310 	browser->b.top_idx = browser->b.index = idx;
311 
312 	while (browser->b.top_idx != 0 && back != 0) {
313 		pos = list_entry(pos->node.prev, struct annotation_line, node);
314 
315 		if (annotation_line__filter(pos))
316 			continue;
317 
318 		--browser->b.top_idx;
319 		--back;
320 	}
321 
322 	browser->b.top = pos;
323 	browser->b.navkeypressed = true;
324 }
325 
annotate_browser__set_rb_top(struct annotate_browser * browser,struct rb_node * nd)326 static void annotate_browser__set_rb_top(struct annotate_browser *browser,
327 					 struct rb_node *nd)
328 {
329 	struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
330 	u32 idx = pos->idx;
331 
332 	if (annotate_opts.hide_src_code)
333 		idx = pos->idx_asm;
334 	annotate_browser__set_top(browser, pos, idx);
335 	browser->curr_hot = nd;
336 }
337 
annotate_browser__calc_percent(struct annotate_browser * browser,struct evsel * evsel)338 static void annotate_browser__calc_percent(struct annotate_browser *browser,
339 					   struct evsel *evsel)
340 {
341 	struct map_symbol *ms = browser->b.priv;
342 	struct symbol *sym = ms->sym;
343 	struct annotation *notes = symbol__annotation(sym);
344 	struct disasm_line *pos;
345 
346 	browser->entries = RB_ROOT;
347 
348 	annotation__lock(notes);
349 
350 	symbol__calc_percent(sym, evsel);
351 
352 	list_for_each_entry(pos, &notes->src->source, al.node) {
353 		double max_percent = 0.0;
354 		int i;
355 
356 		if (pos->al.offset == -1) {
357 			RB_CLEAR_NODE(&pos->al.rb_node);
358 			continue;
359 		}
360 
361 		for (i = 0; i < pos->al.data_nr; i++) {
362 			double percent;
363 
364 			percent = annotation_data__percent(&pos->al.data[i],
365 							   annotate_opts.percent_type);
366 
367 			if (max_percent < percent)
368 				max_percent = percent;
369 		}
370 
371 		if (max_percent < 0.01 && (!pos->al.cycles || pos->al.cycles->ipc == 0)) {
372 			RB_CLEAR_NODE(&pos->al.rb_node);
373 			continue;
374 		}
375 		disasm_rb_tree__insert(browser, &pos->al);
376 	}
377 	annotation__unlock(notes);
378 
379 	browser->curr_hot = rb_last(&browser->entries);
380 }
381 
annotate_browser__find_new_asm_line(struct annotate_browser * browser,int idx_asm)382 static struct annotation_line *annotate_browser__find_new_asm_line(
383 					struct annotate_browser *browser,
384 					int idx_asm)
385 {
386 	struct annotation_line *al;
387 	struct list_head *head = browser->b.entries;
388 
389 	/* find an annotation line in the new list with the same idx_asm */
390 	list_for_each_entry(al, head, node) {
391 		if (al->idx_asm == idx_asm)
392 			return al;
393 	}
394 
395 	/* There are no asm lines */
396 	return NULL;
397 }
398 
annotate_browser__find_next_asm_line(struct annotate_browser * browser,struct annotation_line * al)399 static struct annotation_line *annotate_browser__find_next_asm_line(
400 					struct annotate_browser *browser,
401 					struct annotation_line *al)
402 {
403 	struct annotation_line *it = al;
404 
405 	/* find next asm line */
406 	list_for_each_entry_continue(it, browser->b.entries, node) {
407 		if (it->idx_asm >= 0)
408 			return it;
409 	}
410 
411 	/* no asm line found forwards, try backwards */
412 	it = al;
413 	list_for_each_entry_continue_reverse(it, browser->b.entries, node) {
414 		if (it->idx_asm >= 0)
415 			return it;
416 	}
417 
418 	/* There are no asm lines */
419 	return NULL;
420 }
421 
annotation__has_source(struct annotation * notes)422 static bool annotation__has_source(struct annotation *notes)
423 {
424 	struct annotation_line *al;
425 	bool found_asm = false;
426 
427 	/* Let's skip the first non-asm lines which present regardless of source. */
428 	list_for_each_entry(al, &notes->src->source, node) {
429 		if (al->offset >= 0) {
430 			found_asm = true;
431 			break;
432 		}
433 	}
434 
435 	if (found_asm) {
436 		/* After assembly lines, any line without offset means source. */
437 		list_for_each_entry_continue(al, &notes->src->source, node) {
438 			if (al->offset == -1)
439 				return true;
440 		}
441 	}
442 	return false;
443 }
444 
annotate_browser__toggle_source(struct annotate_browser * browser,struct evsel * evsel)445 static bool annotate_browser__toggle_source(struct annotate_browser *browser,
446 					    struct evsel *evsel)
447 {
448 	struct annotation *notes = browser__annotation(&browser->b);
449 	struct annotation_line *al;
450 	off_t offset = browser->b.index - browser->b.top_idx;
451 
452 	browser->b.seek(&browser->b, offset, SEEK_CUR);
453 	al = list_entry(browser->b.top, struct annotation_line, node);
454 
455 	if (!annotate_opts.annotate_src)
456 		annotate_opts.annotate_src = true;
457 
458 	/*
459 	 * It's about to get source code annotation for the first time.
460 	 * Drop the existing annotation_lines and get the new one with source.
461 	 * And then move to the original line at the same asm index.
462 	 */
463 	if (annotate_opts.hide_src_code && !notes->src->tried_source) {
464 		struct map_symbol *ms = browser->b.priv;
465 		int orig_idx_asm = al->idx_asm;
466 
467 		/* annotate again with source code info */
468 		annotate_opts.hide_src_code = false;
469 		annotated_source__purge(notes->src);
470 		symbol__annotate2(ms, evsel, &browser->arch);
471 		annotate_opts.hide_src_code = true;
472 
473 		/* should be after annotated_source__purge() */
474 		notes->src->tried_source = true;
475 
476 		if (!annotation__has_source(notes))
477 			ui__warning("Annotation has no source code.");
478 
479 		browser->b.entries = &notes->src->source;
480 		al = annotate_browser__find_new_asm_line(browser, orig_idx_asm);
481 		if (unlikely(al == NULL)) {
482 			al = list_first_entry(&notes->src->source,
483 					      struct annotation_line, node);
484 		}
485 		browser->b.seek(&browser->b, al->idx_asm, SEEK_SET);
486 	}
487 
488 	if (annotate_opts.hide_src_code) {
489 		if (al->idx_asm < offset)
490 			offset = al->idx;
491 
492 		browser->b.nr_entries = notes->src->nr_entries;
493 		annotate_opts.hide_src_code = false;
494 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
495 		browser->b.top_idx = al->idx - offset;
496 		browser->b.index = al->idx;
497 	} else {
498 		if (al->idx_asm < 0) {
499 			/* move cursor to next asm line */
500 			al = annotate_browser__find_next_asm_line(browser, al);
501 			if (!al) {
502 				browser->b.seek(&browser->b, -offset, SEEK_CUR);
503 				return false;
504 			}
505 		}
506 
507 		if (al->idx_asm < offset)
508 			offset = al->idx_asm;
509 
510 		browser->b.nr_entries = notes->src->nr_asm_entries;
511 		annotate_opts.hide_src_code = true;
512 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
513 		browser->b.top_idx = al->idx_asm - offset;
514 		browser->b.index = al->idx_asm;
515 	}
516 
517 	if (annotate_opts.hide_src_code_on_title)
518 		annotate_opts.hide_src_code_on_title = false;
519 
520 	return true;
521 }
522 
523 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
524 
annotate_browser__show_full_location(struct ui_browser * browser)525 static void annotate_browser__show_full_location(struct ui_browser *browser)
526 {
527 	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
528 	struct disasm_line *cursor = disasm_line(ab->selection);
529 	struct annotation_line *al = &cursor->al;
530 
531 	if (al->offset != -1)
532 		ui_helpline__puts("Only available for source code lines.");
533 	else if (al->fileloc == NULL)
534 		ui_helpline__puts("No source file location.");
535 	else {
536 		char help_line[SYM_TITLE_MAX_SIZE];
537 		sprintf (help_line, "Source file location: %s", al->fileloc);
538 		ui_helpline__puts(help_line);
539 	}
540 }
541 
ui_browser__init_asm_mode(struct ui_browser * browser)542 static void ui_browser__init_asm_mode(struct ui_browser *browser)
543 {
544 	struct annotation *notes = browser__annotation(browser);
545 	ui_browser__reset_index(browser);
546 	browser->nr_entries = notes->src->nr_asm_entries;
547 }
548 
sym_title(struct symbol * sym,struct map * map,char * title,size_t sz,int percent_type)549 static int sym_title(struct symbol *sym, struct map *map, char *title,
550 		     size_t sz, int percent_type)
551 {
552 	return snprintf(title, sz, "%s  %s [Percent: %s] %s", sym->name,
553 			dso__long_name(map__dso(map)),
554 			percent_type_str(percent_type),
555 			annotate_opts.code_with_type ? "[Type]" : "");
556 }
557 
annotate_browser__show_function_title(struct annotate_browser * browser)558 static void annotate_browser__show_function_title(struct annotate_browser *browser)
559 {
560 	struct ui_browser *b = &browser->b;
561 	struct map_symbol *ms = b->priv;
562 	struct symbol *sym = ms->sym;
563 	char title[SYM_TITLE_MAX_SIZE];
564 
565 	sym_title(sym, ms->map, title, sizeof(title), annotate_opts.percent_type);
566 
567 	ui_browser__gotorc_title(b, 0, 0);
568 	ui_browser__set_color(b, HE_COLORSET_ROOT);
569 	ui_browser__write_nstring(b, title, b->width + 1);
570 }
571 
572 /*
573  * This can be called from external jumps, i.e. jumps from one function
574  * to another, like from the kernel's entry_SYSCALL_64 function to the
575  * swapgs_restore_regs_and_return_to_usermode() function.
576  *
577  * So all we check here is that dl->ops.target.sym is set, if it is, just
578  * go to that function and when exiting from its disassembly, come back
579  * to the calling function.
580  */
annotate_browser__callq(struct annotate_browser * browser,struct evsel * evsel,struct hist_browser_timer * hbt)581 static bool annotate_browser__callq(struct annotate_browser *browser,
582 				    struct evsel *evsel,
583 				    struct hist_browser_timer *hbt)
584 {
585 	struct map_symbol *ms = browser->b.priv, target_ms;
586 	struct disasm_line *dl = disasm_line(browser->selection);
587 	struct annotation *notes;
588 
589 	if (!dl->ops.target.sym) {
590 		ui_helpline__puts("The called function was not found.");
591 		return true;
592 	}
593 
594 	notes = symbol__annotation(dl->ops.target.sym);
595 	annotation__lock(notes);
596 
597 	if (!symbol__hists(dl->ops.target.sym, evsel->evlist->core.nr_entries)) {
598 		annotation__unlock(notes);
599 		ui__warning("Not enough memory for annotating '%s' symbol!\n",
600 			    dl->ops.target.sym->name);
601 		return true;
602 	}
603 
604 	target_ms.maps = ms->maps;
605 	target_ms.map = ms->map;
606 	target_ms.sym = dl->ops.target.sym;
607 	annotation__unlock(notes);
608 	__hist_entry__tui_annotate(browser->he, &target_ms, evsel, hbt, NO_ADDR);
609 
610 	/*
611 	 * The annotate_browser above changed the title with the target function
612 	 * and now it's back to the original function.  Refresh the header line
613 	 * for the original function again.
614 	 */
615 	annotate_browser__show_function_title(browser);
616 	return true;
617 }
618 
619 static
annotate_browser__find_offset(struct annotate_browser * browser,s64 offset,s64 * idx)620 struct disasm_line *annotate_browser__find_offset(struct annotate_browser *browser,
621 					  s64 offset, s64 *idx)
622 {
623 	struct annotation *notes = browser__annotation(&browser->b);
624 	struct disasm_line *pos;
625 
626 	*idx = 0;
627 	list_for_each_entry(pos, &notes->src->source, al.node) {
628 		if (pos->al.offset == offset)
629 			return pos;
630 		if (!annotation_line__filter(&pos->al))
631 			++*idx;
632 	}
633 
634 	return NULL;
635 }
636 
annotate_browser__jump(struct annotate_browser * browser,struct evsel * evsel,struct hist_browser_timer * hbt)637 static bool annotate_browser__jump(struct annotate_browser *browser,
638 				   struct evsel *evsel,
639 				   struct hist_browser_timer *hbt)
640 {
641 	struct disasm_line *dl = disasm_line(browser->selection);
642 	u64 offset;
643 	s64 idx;
644 
645 	if (!ins__is_jump(&dl->ins))
646 		return false;
647 
648 	if (dl->ops.target.outside) {
649 		annotate_browser__callq(browser, evsel, hbt);
650 		return true;
651 	}
652 
653 	offset = dl->ops.target.offset;
654 	dl = annotate_browser__find_offset(browser, offset, &idx);
655 	if (dl == NULL) {
656 		ui_helpline__printf("Invalid jump offset: %" PRIx64, offset);
657 		return true;
658 	}
659 
660 	annotate_browser__set_top(browser, &dl->al, idx);
661 
662 	return true;
663 }
664 
665 static
annotate_browser__find_string(struct annotate_browser * browser,char * s,s64 * idx)666 struct annotation_line *annotate_browser__find_string(struct annotate_browser *browser,
667 					  char *s, s64 *idx)
668 {
669 	struct annotation *notes = browser__annotation(&browser->b);
670 	struct annotation_line *al = browser->selection;
671 
672 	*idx = browser->b.index;
673 	list_for_each_entry_continue(al, &notes->src->source, node) {
674 		if (annotation_line__filter(al))
675 			continue;
676 
677 		++*idx;
678 
679 		if (al->line && strstr(al->line, s) != NULL)
680 			return al;
681 	}
682 
683 	return NULL;
684 }
685 
__annotate_browser__search(struct annotate_browser * browser)686 static bool __annotate_browser__search(struct annotate_browser *browser)
687 {
688 	struct annotation_line *al;
689 	s64 idx;
690 
691 	al = annotate_browser__find_string(browser, browser->search_bf, &idx);
692 	if (al == NULL) {
693 		ui_helpline__puts("String not found!");
694 		return false;
695 	}
696 
697 	annotate_browser__set_top(browser, al, idx);
698 	browser->searching_backwards = false;
699 	return true;
700 }
701 
702 static
annotate_browser__find_string_reverse(struct annotate_browser * browser,char * s,s64 * idx)703 struct annotation_line *annotate_browser__find_string_reverse(struct annotate_browser *browser,
704 						  char *s, s64 *idx)
705 {
706 	struct annotation *notes = browser__annotation(&browser->b);
707 	struct annotation_line *al = browser->selection;
708 
709 	*idx = browser->b.index;
710 	list_for_each_entry_continue_reverse(al, &notes->src->source, node) {
711 		if (annotation_line__filter(al))
712 			continue;
713 
714 		--*idx;
715 
716 		if (al->line && strstr(al->line, s) != NULL)
717 			return al;
718 	}
719 
720 	return NULL;
721 }
722 
__annotate_browser__search_reverse(struct annotate_browser * browser)723 static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
724 {
725 	struct annotation_line *al;
726 	s64 idx;
727 
728 	al = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
729 	if (al == NULL) {
730 		ui_helpline__puts("String not found!");
731 		return false;
732 	}
733 
734 	annotate_browser__set_top(browser, al, idx);
735 	browser->searching_backwards = true;
736 	return true;
737 }
738 
annotate_browser__search_window(struct annotate_browser * browser,int delay_secs)739 static bool annotate_browser__search_window(struct annotate_browser *browser,
740 					    int delay_secs)
741 {
742 	if (ui_browser__input_window("Search", "String: ", browser->search_bf,
743 				     "ENTER: OK, ESC: Cancel",
744 				     delay_secs * 2) != K_ENTER ||
745 	    !*browser->search_bf)
746 		return false;
747 
748 	return true;
749 }
750 
annotate_browser__search(struct annotate_browser * browser,int delay_secs)751 static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
752 {
753 	if (annotate_browser__search_window(browser, delay_secs))
754 		return __annotate_browser__search(browser);
755 
756 	return false;
757 }
758 
annotate_browser__continue_search(struct annotate_browser * browser,int delay_secs)759 static bool annotate_browser__continue_search(struct annotate_browser *browser,
760 					      int delay_secs)
761 {
762 	if (!*browser->search_bf)
763 		return annotate_browser__search(browser, delay_secs);
764 
765 	return __annotate_browser__search(browser);
766 }
767 
annotate_browser__search_reverse(struct annotate_browser * browser,int delay_secs)768 static bool annotate_browser__search_reverse(struct annotate_browser *browser,
769 					   int delay_secs)
770 {
771 	if (annotate_browser__search_window(browser, delay_secs))
772 		return __annotate_browser__search_reverse(browser);
773 
774 	return false;
775 }
776 
777 static
annotate_browser__continue_search_reverse(struct annotate_browser * browser,int delay_secs)778 bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
779 					       int delay_secs)
780 {
781 	if (!*browser->search_bf)
782 		return annotate_browser__search_reverse(browser, delay_secs);
783 
784 	return __annotate_browser__search_reverse(browser);
785 }
786 
annotate_browser__show(struct annotate_browser * browser,char * title,const char * help)787 static int annotate_browser__show(struct annotate_browser *browser, char *title, const char *help)
788 {
789 	if (ui_browser__show(&browser->b, title, help) < 0)
790 		return -1;
791 
792 	annotate_browser__show_function_title(browser);
793 	return 0;
794 }
795 
796 static void
switch_percent_type(struct annotation_options * opts,bool base)797 switch_percent_type(struct annotation_options *opts, bool base)
798 {
799 	switch (opts->percent_type) {
800 	case PERCENT_HITS_LOCAL:
801 		if (base)
802 			opts->percent_type = PERCENT_PERIOD_LOCAL;
803 		else
804 			opts->percent_type = PERCENT_HITS_GLOBAL;
805 		break;
806 	case PERCENT_HITS_GLOBAL:
807 		if (base)
808 			opts->percent_type = PERCENT_PERIOD_GLOBAL;
809 		else
810 			opts->percent_type = PERCENT_HITS_LOCAL;
811 		break;
812 	case PERCENT_PERIOD_LOCAL:
813 		if (base)
814 			opts->percent_type = PERCENT_HITS_LOCAL;
815 		else
816 			opts->percent_type = PERCENT_PERIOD_GLOBAL;
817 		break;
818 	case PERCENT_PERIOD_GLOBAL:
819 		if (base)
820 			opts->percent_type = PERCENT_HITS_GLOBAL;
821 		else
822 			opts->percent_type = PERCENT_PERIOD_LOCAL;
823 		break;
824 	default:
825 		WARN_ON(1);
826 	}
827 }
828 
annotate__scnprintf_title(struct hists * hists,char * bf,size_t size)829 static int annotate__scnprintf_title(struct hists *hists, char *bf, size_t size)
830 {
831 	int printed = hists__scnprintf_title(hists, bf, size);
832 
833 	if (!annotate_opts.hide_src_code_on_title) {
834 		printed += scnprintf(bf + printed, size - printed, " [source: %s]",
835 				     annotate_opts.hide_src_code ? "OFF" : "On");
836 	}
837 
838 	return printed;
839 }
840 
annotate_browser__debuginfo_warning(struct annotate_browser * browser)841 static void annotate_browser__debuginfo_warning(struct annotate_browser *browser)
842 {
843 	struct map_symbol *ms = browser->b.priv;
844 	struct dso *dso = map__dso(ms->map);
845 
846 	if (browser->dbg == NULL && annotate_opts.code_with_type &&
847 	    !dso__debuginfo_warned(dso)) {
848 		ui__warning("DWARF debuginfo not found.\n\n"
849 			    "Data-type in this DSO will not be displayed.\n"
850 			    "Please make sure to have debug information.");
851 		dso__set_debuginfo_warned(dso);
852 	}
853 }
854 
annotate_browser__curr_hot_offset(struct annotate_browser * browser)855 static s64 annotate_browser__curr_hot_offset(struct annotate_browser *browser)
856 {
857 	struct annotation_line *al = NULL;
858 
859 	if (browser->curr_hot)
860 		al = rb_entry(browser->curr_hot, struct annotation_line, rb_node);
861 
862 	return al ? al->offset : 0;
863 }
864 
annotate_browser__symbol_annotate_error(struct annotate_browser * browser,int err)865 static void annotate_browser__symbol_annotate_error(struct annotate_browser *browser, int err)
866 {
867 	struct map_symbol *ms = browser->b.priv;
868 	struct symbol *sym = ms->sym;
869 	struct dso *dso = map__dso(ms->map);
870 	char msg[BUFSIZ];
871 
872 	dso__set_annotate_warned(dso);
873 	symbol__strerror_disassemble(ms, err, msg, sizeof(msg));
874 	ui__error("Couldn't annotate %s:\n%s", sym->name, msg);
875 }
876 
annotate_browser__run(struct annotate_browser * browser,struct evsel * evsel,struct hist_browser_timer * hbt)877 static int annotate_browser__run(struct annotate_browser *browser,
878 				 struct evsel *evsel,
879 				 struct hist_browser_timer *hbt)
880 {
881 	struct rb_node *nd = NULL;
882 	struct hists *hists = evsel__hists(evsel);
883 	struct map_symbol *ms = browser->b.priv;
884 	struct symbol *sym = ms->sym;
885 	struct annotation *notes = symbol__annotation(ms->sym);
886 	const char *help = "Press 'h' for help on key bindings";
887 	int delay_secs = hbt ? hbt->refresh : 0;
888 	char *br_cntr_text = NULL;
889 	char title[256];
890 	int key;
891 
892 	annotate__scnprintf_title(hists, title, sizeof(title));
893 	if (annotate_browser__show(browser, title, help) < 0)
894 		return -1;
895 
896 	annotate_browser__calc_percent(browser, evsel);
897 
898 	if (browser->selection != NULL) {
899 		browser->curr_hot = &browser->selection->rb_node;
900 		browser->b.use_navkeypressed = false;
901 	}
902 
903 	if (browser->curr_hot) {
904 		annotate_browser__set_rb_top(browser, browser->curr_hot);
905 		browser->b.navkeypressed = false;
906 	}
907 
908 	nd = browser->curr_hot;
909 
910 	annotation_br_cntr_abbr_list(&br_cntr_text, evsel, false);
911 
912 	annotate_browser__debuginfo_warning(browser);
913 
914 	while (1) {
915 		key = ui_browser__run(&browser->b, delay_secs);
916 
917 		if (delay_secs != 0) {
918 			annotate_browser__calc_percent(browser, evsel);
919 			/*
920 			 * Current line focus got out of the list of most active
921 			 * lines, NULL it so that if TAB|UNTAB is pressed, we
922 			 * move to curr_hot (current hottest line).
923 			 */
924 			if (nd != NULL && RB_EMPTY_NODE(nd))
925 				nd = NULL;
926 		}
927 
928 		switch (key) {
929 		case K_TIMER:
930 			if (hbt)
931 				hbt->timer(hbt->arg);
932 
933 			if (delay_secs != 0) {
934 				symbol__annotate_decay_histogram(sym, evsel);
935 				annotate__scnprintf_title(hists, title, sizeof(title));
936 				annotate_browser__show(browser, title, help);
937 			}
938 			continue;
939 		case K_TAB:
940 			if (nd != NULL) {
941 				nd = rb_prev(nd);
942 				if (nd == NULL)
943 					nd = rb_last(&browser->entries);
944 			} else
945 				nd = browser->curr_hot;
946 			break;
947 		case K_UNTAB:
948 			if (nd != NULL) {
949 				nd = rb_next(nd);
950 				if (nd == NULL)
951 					nd = rb_first(&browser->entries);
952 			} else
953 				nd = browser->curr_hot;
954 			break;
955 		case K_F1:
956 		case 'h':
957 			ui_browser__help_window(&browser->b,
958 		"UP/DOWN/PGUP\n"
959 		"PGDN/SPACE    Navigate\n"
960 		"</>           Move to prev/next symbol\n"
961 		"q/ESC/CTRL+C  Exit\n\n"
962 		"ENTER         Go to target\n"
963 		"H             Go to hottest instruction\n"
964 		"TAB/shift+TAB Cycle thru hottest instructions\n"
965 		"j             Toggle showing jump to target arrows\n"
966 		"J             Toggle showing number of jump sources on targets\n"
967 		"n             Search next string\n"
968 		"o             Toggle disassembler output/simplified view\n"
969 		"O             Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
970 		"s             Toggle source code view\n"
971 		"t             Circulate percent, total period, samples view\n"
972 		"c             Show min/max cycle\n"
973 		"/             Search string\n"
974 		"k             Toggle line numbers\n"
975 		"l             Show full source file location\n"
976 		"P             Print to [symbol_name].annotation file.\n"
977 		"r             Run available scripts\n"
978 		"p             Toggle percent type [local/global]\n"
979 		"b             Toggle percent base [period/hits]\n"
980 		"B             Branch counter abbr list (Optional)\n"
981 		"?             Search string backwards\n"
982 		"f             Toggle showing offsets to full address\n"
983 		"T             Toggle data type display\n");
984 			continue;
985 		case 'r':
986 			script_browse(NULL, NULL);
987 			annotate_browser__show(browser, title, help);
988 			continue;
989 		case 'k':
990 			annotate_opts.show_linenr = !annotate_opts.show_linenr;
991 			continue;
992 		case 'l':
993 			annotate_browser__show_full_location (&browser->b);
994 			continue;
995 		case 'H':
996 			nd = browser->curr_hot;
997 			break;
998 		case 's': {
999 			struct annotation_line *al = NULL;
1000 			s64 offset = annotate_browser__curr_hot_offset(browser);
1001 
1002 			if (annotate_browser__toggle_source(browser, evsel))
1003 				ui_helpline__puts(help);
1004 
1005 			/* Update the annotation browser's rb_tree, and reset the nd */
1006 			annotate_browser__calc_percent(browser, evsel);
1007 			/* Try to find the same asm line as before */
1008 			al = annotated_source__get_line(notes->src, offset);
1009 			browser->curr_hot = al ? &al->rb_node : NULL;
1010 			nd = browser->curr_hot;
1011 
1012 			annotate__scnprintf_title(hists, title, sizeof(title));
1013 			annotate_browser__show(browser, title, help);
1014 			continue;
1015 		}
1016 		case 'o':
1017 			annotate_opts.use_offset = !annotate_opts.use_offset;
1018 			annotation__update_column_widths(notes);
1019 			continue;
1020 		case 'O':
1021 			if (++annotate_opts.offset_level > ANNOTATION__MAX_OFFSET_LEVEL)
1022 				annotate_opts.offset_level = ANNOTATION__MIN_OFFSET_LEVEL;
1023 			continue;
1024 		case 'j':
1025 			annotate_opts.jump_arrows = !annotate_opts.jump_arrows;
1026 			continue;
1027 		case 'J':
1028 			annotate_opts.show_nr_jumps = !annotate_opts.show_nr_jumps;
1029 			annotation__update_column_widths(notes);
1030 			continue;
1031 		case '/':
1032 			if (annotate_browser__search(browser, delay_secs)) {
1033 show_help:
1034 				ui_helpline__puts(help);
1035 			}
1036 			continue;
1037 		case 'n':
1038 			if (browser->searching_backwards ?
1039 			    annotate_browser__continue_search_reverse(browser, delay_secs) :
1040 			    annotate_browser__continue_search(browser, delay_secs))
1041 				goto show_help;
1042 			continue;
1043 		case '?':
1044 			if (annotate_browser__search_reverse(browser, delay_secs))
1045 				goto show_help;
1046 			continue;
1047 		case 'D': {
1048 			static int seq;
1049 			ui_helpline__pop();
1050 			ui_helpline__fpush("%d: nr_ent=%d, height=%d, idx=%d, top_idx=%d, nr_asm_entries=%d",
1051 					   seq++, browser->b.nr_entries,
1052 					   browser->b.height,
1053 					   browser->b.index,
1054 					   browser->b.top_idx,
1055 					   notes->src->nr_asm_entries);
1056 		}
1057 			continue;
1058 		case K_ENTER:
1059 		case K_RIGHT:
1060 		{
1061 			struct disasm_line *dl = disasm_line(browser->selection);
1062 
1063 			if (browser->selection == NULL)
1064 				ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
1065 			else if (browser->selection->offset == -1)
1066 				ui_helpline__puts("Actions are only available for assembly lines.");
1067 			else if (!dl->ins.ops)
1068 				goto show_sup_ins;
1069 			else if (ins__is_ret(&dl->ins))
1070 				goto out;
1071 			else if (!(annotate_browser__jump(browser, evsel, hbt) ||
1072 				     annotate_browser__callq(browser, evsel, hbt))) {
1073 show_sup_ins:
1074 				ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
1075 			}
1076 			continue;
1077 		}
1078 		case 'P':
1079 			map_symbol__annotation_dump(ms, evsel, browser->he);
1080 			continue;
1081 		case 't':
1082 			if (symbol_conf.show_total_period) {
1083 				symbol_conf.show_total_period = false;
1084 				symbol_conf.show_nr_samples = true;
1085 			} else if (symbol_conf.show_nr_samples)
1086 				symbol_conf.show_nr_samples = false;
1087 			else
1088 				symbol_conf.show_total_period = true;
1089 			annotation__update_column_widths(notes);
1090 			continue;
1091 		case 'c':
1092 			if (annotate_opts.show_minmax_cycle)
1093 				annotate_opts.show_minmax_cycle = false;
1094 			else
1095 				annotate_opts.show_minmax_cycle = true;
1096 			annotation__update_column_widths(notes);
1097 			continue;
1098 		case 'p':
1099 		case 'b':
1100 			switch_percent_type(&annotate_opts, key == 'b');
1101 			annotate__scnprintf_title(hists, title, sizeof(title));
1102 			annotate_browser__show(browser, title, help);
1103 			continue;
1104 		case 'B':
1105 			if (br_cntr_text)
1106 				ui_browser__help_window(&browser->b, br_cntr_text);
1107 			else {
1108 				ui_browser__help_window(&browser->b,
1109 							"\n The branch counter is not available.\n");
1110 			}
1111 			continue;
1112 		case 'f':
1113 			annotation__toggle_full_addr(notes, ms);
1114 			continue;
1115 		case 'T':
1116 			annotate_opts.code_with_type ^= 1;
1117 			if (browser->dbg == NULL)
1118 				browser->dbg = dso__debuginfo(map__dso(ms->map));
1119 			if (browser->type_hash == NULL) {
1120 				browser->type_hash = hashmap__new(type_hash, type_equal,
1121 								  /*ctx=*/NULL);
1122 			}
1123 			annotate_browser__show(browser, title, help);
1124 			annotate_browser__debuginfo_warning(browser);
1125 			continue;
1126 		case K_LEFT:
1127 		case '<':
1128 		case '>':
1129 		case K_ESC:
1130 		case 'q':
1131 		case CTRL('c'):
1132 			goto out;
1133 		default:
1134 			ui_browser__warn_unhandled_hotkey(&browser->b, key, delay_secs, ", use 'h'/F1 to see actions");
1135 			continue;
1136 		}
1137 
1138 		if (nd != NULL)
1139 			annotate_browser__set_rb_top(browser, nd);
1140 	}
1141 out:
1142 	ui_browser__hide(&browser->b);
1143 	free(br_cntr_text);
1144 	return key;
1145 }
1146 
hist_entry__tui_annotate(struct hist_entry * he,struct evsel * evsel,struct hist_browser_timer * hbt,u64 al_addr)1147 int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel,
1148 			     struct hist_browser_timer *hbt, u64 al_addr)
1149 {
1150 	/* reset abort key so that it can get Ctrl-C as a key */
1151 	SLang_reset_tty();
1152 	SLang_init_tty(0, 0, 0);
1153 	SLtty_set_suspend_state(true);
1154 
1155 	return __hist_entry__tui_annotate(he, &he->ms, evsel, hbt, al_addr);
1156 }
1157 
__hist_entry__tui_annotate(struct hist_entry * he,struct map_symbol * ms,struct evsel * evsel,struct hist_browser_timer * hbt,u64 al_addr)1158 int __hist_entry__tui_annotate(struct hist_entry *he, struct map_symbol *ms,
1159 			       struct evsel *evsel,
1160 			       struct hist_browser_timer *hbt, u64 al_addr)
1161 {
1162 	struct symbol *sym = ms->sym;
1163 	struct annotation *notes = symbol__annotation(sym);
1164 	struct annotate_browser browser = {
1165 		.b = {
1166 			.refresh = annotate_browser__refresh,
1167 			.seek	 = ui_browser__list_head_seek,
1168 			.write	 = annotate_browser__write,
1169 			.filter  = disasm_line__filter,
1170 			.extra_title_lines = 1, /* for hists__scnprintf_title() */
1171 			.priv	 = ms,
1172 			.use_navkeypressed = true,
1173 		},
1174 		.he = he,
1175 		.evsel = evsel,
1176 	};
1177 	struct dso *dso;
1178 	int ret = -1, err;
1179 	int not_annotated = list_empty(&notes->src->source);
1180 
1181 	if (sym == NULL)
1182 		return -1;
1183 
1184 	dso = map__dso(ms->map);
1185 	if (dso__annotate_warned(dso))
1186 		return -1;
1187 
1188 	if (not_annotated || !sym->annotate2) {
1189 		err = symbol__annotate2(ms, evsel, &browser.arch);
1190 		if (err) {
1191 			annotate_browser__symbol_annotate_error(&browser, err);
1192 			return -1;
1193 		}
1194 
1195 		if (!annotate_opts.hide_src_code) {
1196 			notes->src->tried_source = true;
1197 			if (!annotation__has_source(notes))
1198 				ui__warning("Annotation has no source code.");
1199 		}
1200 	} else {
1201 		err = evsel__get_arch(evsel, &browser.arch);
1202 		if (err) {
1203 			annotate_browser__symbol_annotate_error(&browser, err);
1204 			return -1;
1205 		}
1206 	}
1207 
1208 	/* Copy necessary information when it's called from perf top */
1209 	if (hbt != NULL && he != &annotate_he) {
1210 		annotate_he.hists = he->hists;
1211 		annotate_he.thread = thread__get(he->thread);
1212 		annotate_he.cpumode = he->cpumode;
1213 		map_symbol__copy(&annotate_he.ms, ms);
1214 
1215 		browser.he = &annotate_he;
1216 	}
1217 
1218 	ui_helpline__push("Press ESC to exit");
1219 
1220 	if (annotate_opts.code_with_type) {
1221 		browser.dbg = dso__debuginfo(dso);
1222 		browser.type_hash = hashmap__new(type_hash, type_equal, /*ctx=*/NULL);
1223 	}
1224 
1225 	browser.b.width = notes->src->widths.max_line_len;
1226 	browser.b.nr_entries = notes->src->nr_entries;
1227 	browser.b.entries = &notes->src->source;
1228 	browser.b.width += 18; /* Percentage */
1229 
1230 	if (annotate_opts.hide_src_code)
1231 		ui_browser__init_asm_mode(&browser.b);
1232 
1233 	/*
1234 	 * If al_addr is set, it means that there should be a line
1235 	 * intentionally selected, not based on the percentages
1236 	 * which caculated by the event sampling. In this case, we
1237 	 * convey this information into the browser selection, where
1238 	 * the selection in other cases should be empty.
1239 	 */
1240 	if (al_addr != NO_ADDR) {
1241 		struct annotation_line *al = annotated_source__get_line(notes->src,
1242 			al_addr - sym->start);
1243 
1244 		browser.selection = al;
1245 	}
1246 
1247 	ret = annotate_browser__run(&browser, evsel, hbt);
1248 
1249 	debuginfo__delete(browser.dbg);
1250 
1251 	if (!IS_ERR_OR_NULL(browser.type_hash)) {
1252 		struct hashmap_entry *cur;
1253 		size_t bkt;
1254 
1255 		hashmap__for_each_entry(browser.type_hash, cur, bkt)
1256 			zfree(&cur->pvalue);
1257 		hashmap__free(browser.type_hash);
1258 	}
1259 
1260 	if (not_annotated && !notes->src->tried_source)
1261 		annotated_source__purge(notes->src);
1262 
1263 	if (hbt != NULL && he != &annotate_he) {
1264 		thread__zput(annotate_he.thread);
1265 		map_symbol__exit(&annotate_he.ms);
1266 	}
1267 
1268 	return ret;
1269 }
1270