Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme (at) redhat.com>
      3  *
      4  * Parts came from builtin-annotate.c, see those files for further
      5  * copyright notes.
      6  *
      7  * Released under the GPL v2. (and only v2, not any later version)
      8  */
      9 
     10 #include "util.h"
     11 #include "build-id.h"
     12 #include "color.h"
     13 #include "cache.h"
     14 #include "symbol.h"
     15 #include "debug.h"
     16 #include "annotate.h"
     17 #include "evsel.h"
     18 #include <pthread.h>
     19 #include <linux/bitops.h>
     20 
     21 const char 	*disassembler_style;
     22 const char	*objdump_path;
     23 
     24 static struct ins *ins__find(const char *name);
     25 static int disasm_line__parse(char *line, char **namep, char **rawp);
     26 
     27 static void ins__delete(struct ins_operands *ops)
     28 {
     29 	free(ops->source.raw);
     30 	free(ops->source.name);
     31 	free(ops->target.raw);
     32 	free(ops->target.name);
     33 }
     34 
     35 static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
     36 			      struct ins_operands *ops)
     37 {
     38 	return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw);
     39 }
     40 
     41 int ins__scnprintf(struct ins *ins, char *bf, size_t size,
     42 		  struct ins_operands *ops)
     43 {
     44 	if (ins->ops->scnprintf)
     45 		return ins->ops->scnprintf(ins, bf, size, ops);
     46 
     47 	return ins__raw_scnprintf(ins, bf, size, ops);
     48 }
     49 
     50 static int call__parse(struct ins_operands *ops)
     51 {
     52 	char *endptr, *tok, *name;
     53 
     54 	ops->target.addr = strtoull(ops->raw, &endptr, 16);
     55 
     56 	name = strchr(endptr, '<');
     57 	if (name == NULL)
     58 		goto indirect_call;
     59 
     60 	name++;
     61 
     62 	tok = strchr(name, '>');
     63 	if (tok == NULL)
     64 		return -1;
     65 
     66 	*tok = '\0';
     67 	ops->target.name = strdup(name);
     68 	*tok = '>';
     69 
     70 	return ops->target.name == NULL ? -1 : 0;
     71 
     72 indirect_call:
     73 	tok = strchr(endptr, '(');
     74 	if (tok != NULL) {
     75 		ops->target.addr = 0;
     76 		return 0;
     77 	}
     78 
     79 	tok = strchr(endptr, '*');
     80 	if (tok == NULL)
     81 		return -1;
     82 
     83 	ops->target.addr = strtoull(tok + 1, NULL, 16);
     84 	return 0;
     85 }
     86 
     87 static int call__scnprintf(struct ins *ins, char *bf, size_t size,
     88 			   struct ins_operands *ops)
     89 {
     90 	if (ops->target.name)
     91 		return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name);
     92 
     93 	if (ops->target.addr == 0)
     94 		return ins__raw_scnprintf(ins, bf, size, ops);
     95 
     96 	return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr);
     97 }
     98 
     99 static struct ins_ops call_ops = {
    100 	.parse	   = call__parse,
    101 	.scnprintf = call__scnprintf,
    102 };
    103 
    104 bool ins__is_call(const struct ins *ins)
    105 {
    106 	return ins->ops == &call_ops;
    107 }
    108 
    109 static int jump__parse(struct ins_operands *ops)
    110 {
    111 	const char *s = strchr(ops->raw, '+');
    112 
    113 	ops->target.addr = strtoull(ops->raw, NULL, 16);
    114 
    115 	if (s++ != NULL)
    116 		ops->target.offset = strtoull(s, NULL, 16);
    117 	else
    118 		ops->target.offset = UINT64_MAX;
    119 
    120 	return 0;
    121 }
    122 
    123 static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
    124 			   struct ins_operands *ops)
    125 {
    126 	return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset);
    127 }
    128 
    129 static struct ins_ops jump_ops = {
    130 	.parse	   = jump__parse,
    131 	.scnprintf = jump__scnprintf,
    132 };
    133 
    134 bool ins__is_jump(const struct ins *ins)
    135 {
    136 	return ins->ops == &jump_ops;
    137 }
    138 
    139 static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
    140 {
    141 	char *endptr, *name, *t;
    142 
    143 	if (strstr(raw, "(%rip)") == NULL)
    144 		return 0;
    145 
    146 	*addrp = strtoull(comment, &endptr, 16);
    147 	name = strchr(endptr, '<');
    148 	if (name == NULL)
    149 		return -1;
    150 
    151 	name++;
    152 
    153 	t = strchr(name, '>');
    154 	if (t == NULL)
    155 		return 0;
    156 
    157 	*t = '\0';
    158 	*namep = strdup(name);
    159 	*t = '>';
    160 
    161 	return 0;
    162 }
    163 
    164 static int lock__parse(struct ins_operands *ops)
    165 {
    166 	char *name;
    167 
    168 	ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
    169 	if (ops->locked.ops == NULL)
    170 		return 0;
    171 
    172 	if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0)
    173 		goto out_free_ops;
    174 
    175 	ops->locked.ins = ins__find(name);
    176 	if (ops->locked.ins == NULL)
    177 		goto out_free_ops;
    178 
    179 	if (!ops->locked.ins->ops)
    180 		return 0;
    181 
    182 	if (ops->locked.ins->ops->parse)
    183 		ops->locked.ins->ops->parse(ops->locked.ops);
    184 
    185 	return 0;
    186 
    187 out_free_ops:
    188 	free(ops->locked.ops);
    189 	ops->locked.ops = NULL;
    190 	return 0;
    191 }
    192 
    193 static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
    194 			   struct ins_operands *ops)
    195 {
    196 	int printed;
    197 
    198 	if (ops->locked.ins == NULL)
    199 		return ins__raw_scnprintf(ins, bf, size, ops);
    200 
    201 	printed = scnprintf(bf, size, "%-6.6s ", ins->name);
    202 	return printed + ins__scnprintf(ops->locked.ins, bf + printed,
    203 					size - printed, ops->locked.ops);
    204 }
    205 
    206 static void lock__delete(struct ins_operands *ops)
    207 {
    208 	free(ops->locked.ops);
    209 	free(ops->target.raw);
    210 	free(ops->target.name);
    211 }
    212 
    213 static struct ins_ops lock_ops = {
    214 	.free	   = lock__delete,
    215 	.parse	   = lock__parse,
    216 	.scnprintf = lock__scnprintf,
    217 };
    218 
    219 static int mov__parse(struct ins_operands *ops)
    220 {
    221 	char *s = strchr(ops->raw, ','), *target, *comment, prev;
    222 
    223 	if (s == NULL)
    224 		return -1;
    225 
    226 	*s = '\0';
    227 	ops->source.raw = strdup(ops->raw);
    228 	*s = ',';
    229 
    230 	if (ops->source.raw == NULL)
    231 		return -1;
    232 
    233 	target = ++s;
    234 
    235 	while (s[0] != '\0' && !isspace(s[0]))
    236 		++s;
    237 	prev = *s;
    238 	*s = '\0';
    239 
    240 	ops->target.raw = strdup(target);
    241 	*s = prev;
    242 
    243 	if (ops->target.raw == NULL)
    244 		goto out_free_source;
    245 
    246 	comment = strchr(s, '#');
    247 	if (comment == NULL)
    248 		return 0;
    249 
    250 	while (comment[0] != '\0' && isspace(comment[0]))
    251 		++comment;
    252 
    253 	comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name);
    254 	comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
    255 
    256 	return 0;
    257 
    258 out_free_source:
    259 	free(ops->source.raw);
    260 	ops->source.raw = NULL;
    261 	return -1;
    262 }
    263 
    264 static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
    265 			   struct ins_operands *ops)
    266 {
    267 	return scnprintf(bf, size, "%-6.6s %s,%s", ins->name,
    268 			 ops->source.name ?: ops->source.raw,
    269 			 ops->target.name ?: ops->target.raw);
    270 }
    271 
    272 static struct ins_ops mov_ops = {
    273 	.parse	   = mov__parse,
    274 	.scnprintf = mov__scnprintf,
    275 };
    276 
    277 static int dec__parse(struct ins_operands *ops)
    278 {
    279 	char *target, *comment, *s, prev;
    280 
    281 	target = s = ops->raw;
    282 
    283 	while (s[0] != '\0' && !isspace(s[0]))
    284 		++s;
    285 	prev = *s;
    286 	*s = '\0';
    287 
    288 	ops->target.raw = strdup(target);
    289 	*s = prev;
    290 
    291 	if (ops->target.raw == NULL)
    292 		return -1;
    293 
    294 	comment = strchr(s, '#');
    295 	if (comment == NULL)
    296 		return 0;
    297 
    298 	while (comment[0] != '\0' && isspace(comment[0]))
    299 		++comment;
    300 
    301 	comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
    302 
    303 	return 0;
    304 }
    305 
    306 static int dec__scnprintf(struct ins *ins, char *bf, size_t size,
    307 			   struct ins_operands *ops)
    308 {
    309 	return scnprintf(bf, size, "%-6.6s %s", ins->name,
    310 			 ops->target.name ?: ops->target.raw);
    311 }
    312 
    313 static struct ins_ops dec_ops = {
    314 	.parse	   = dec__parse,
    315 	.scnprintf = dec__scnprintf,
    316 };
    317 
    318 static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size,
    319 			  struct ins_operands *ops __maybe_unused)
    320 {
    321 	return scnprintf(bf, size, "%-6.6s", "nop");
    322 }
    323 
    324 static struct ins_ops nop_ops = {
    325 	.scnprintf = nop__scnprintf,
    326 };
    327 
    328 /*
    329  * Must be sorted by name!
    330  */
    331 static struct ins instructions[] = {
    332 	{ .name = "add",   .ops  = &mov_ops, },
    333 	{ .name = "addl",  .ops  = &mov_ops, },
    334 	{ .name = "addq",  .ops  = &mov_ops, },
    335 	{ .name = "addw",  .ops  = &mov_ops, },
    336 	{ .name = "and",   .ops  = &mov_ops, },
    337 	{ .name = "bts",   .ops  = &mov_ops, },
    338 	{ .name = "call",  .ops  = &call_ops, },
    339 	{ .name = "callq", .ops  = &call_ops, },
    340 	{ .name = "cmp",   .ops  = &mov_ops, },
    341 	{ .name = "cmpb",  .ops  = &mov_ops, },
    342 	{ .name = "cmpl",  .ops  = &mov_ops, },
    343 	{ .name = "cmpq",  .ops  = &mov_ops, },
    344 	{ .name = "cmpw",  .ops  = &mov_ops, },
    345 	{ .name = "cmpxch", .ops  = &mov_ops, },
    346 	{ .name = "dec",   .ops  = &dec_ops, },
    347 	{ .name = "decl",  .ops  = &dec_ops, },
    348 	{ .name = "imul",  .ops  = &mov_ops, },
    349 	{ .name = "inc",   .ops  = &dec_ops, },
    350 	{ .name = "incl",  .ops  = &dec_ops, },
    351 	{ .name = "ja",	   .ops  = &jump_ops, },
    352 	{ .name = "jae",   .ops  = &jump_ops, },
    353 	{ .name = "jb",	   .ops  = &jump_ops, },
    354 	{ .name = "jbe",   .ops  = &jump_ops, },
    355 	{ .name = "jc",	   .ops  = &jump_ops, },
    356 	{ .name = "jcxz",  .ops  = &jump_ops, },
    357 	{ .name = "je",	   .ops  = &jump_ops, },
    358 	{ .name = "jecxz", .ops  = &jump_ops, },
    359 	{ .name = "jg",	   .ops  = &jump_ops, },
    360 	{ .name = "jge",   .ops  = &jump_ops, },
    361 	{ .name = "jl",    .ops  = &jump_ops, },
    362 	{ .name = "jle",   .ops  = &jump_ops, },
    363 	{ .name = "jmp",   .ops  = &jump_ops, },
    364 	{ .name = "jmpq",  .ops  = &jump_ops, },
    365 	{ .name = "jna",   .ops  = &jump_ops, },
    366 	{ .name = "jnae",  .ops  = &jump_ops, },
    367 	{ .name = "jnb",   .ops  = &jump_ops, },
    368 	{ .name = "jnbe",  .ops  = &jump_ops, },
    369 	{ .name = "jnc",   .ops  = &jump_ops, },
    370 	{ .name = "jne",   .ops  = &jump_ops, },
    371 	{ .name = "jng",   .ops  = &jump_ops, },
    372 	{ .name = "jnge",  .ops  = &jump_ops, },
    373 	{ .name = "jnl",   .ops  = &jump_ops, },
    374 	{ .name = "jnle",  .ops  = &jump_ops, },
    375 	{ .name = "jno",   .ops  = &jump_ops, },
    376 	{ .name = "jnp",   .ops  = &jump_ops, },
    377 	{ .name = "jns",   .ops  = &jump_ops, },
    378 	{ .name = "jnz",   .ops  = &jump_ops, },
    379 	{ .name = "jo",	   .ops  = &jump_ops, },
    380 	{ .name = "jp",	   .ops  = &jump_ops, },
    381 	{ .name = "jpe",   .ops  = &jump_ops, },
    382 	{ .name = "jpo",   .ops  = &jump_ops, },
    383 	{ .name = "jrcxz", .ops  = &jump_ops, },
    384 	{ .name = "js",	   .ops  = &jump_ops, },
    385 	{ .name = "jz",	   .ops  = &jump_ops, },
    386 	{ .name = "lea",   .ops  = &mov_ops, },
    387 	{ .name = "lock",  .ops  = &lock_ops, },
    388 	{ .name = "mov",   .ops  = &mov_ops, },
    389 	{ .name = "movb",  .ops  = &mov_ops, },
    390 	{ .name = "movdqa",.ops  = &mov_ops, },
    391 	{ .name = "movl",  .ops  = &mov_ops, },
    392 	{ .name = "movq",  .ops  = &mov_ops, },
    393 	{ .name = "movslq", .ops  = &mov_ops, },
    394 	{ .name = "movzbl", .ops  = &mov_ops, },
    395 	{ .name = "movzwl", .ops  = &mov_ops, },
    396 	{ .name = "nop",   .ops  = &nop_ops, },
    397 	{ .name = "nopl",  .ops  = &nop_ops, },
    398 	{ .name = "nopw",  .ops  = &nop_ops, },
    399 	{ .name = "or",    .ops  = &mov_ops, },
    400 	{ .name = "orl",   .ops  = &mov_ops, },
    401 	{ .name = "test",  .ops  = &mov_ops, },
    402 	{ .name = "testb", .ops  = &mov_ops, },
    403 	{ .name = "testl", .ops  = &mov_ops, },
    404 	{ .name = "xadd",  .ops  = &mov_ops, },
    405 	{ .name = "xbeginl", .ops  = &jump_ops, },
    406 	{ .name = "xbeginq", .ops  = &jump_ops, },
    407 };
    408 
    409 static int ins__cmp(const void *name, const void *insp)
    410 {
    411 	const struct ins *ins = insp;
    412 
    413 	return strcmp(name, ins->name);
    414 }
    415 
    416 static struct ins *ins__find(const char *name)
    417 {
    418 	const int nmemb = ARRAY_SIZE(instructions);
    419 
    420 	return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp);
    421 }
    422 
    423 int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym)
    424 {
    425 	struct annotation *notes = symbol__annotation(sym);
    426 	pthread_mutex_init(&notes->lock, NULL);
    427 	return 0;
    428 }
    429 
    430 int symbol__alloc_hist(struct symbol *sym)
    431 {
    432 	struct annotation *notes = symbol__annotation(sym);
    433 	const size_t size = symbol__size(sym);
    434 	size_t sizeof_sym_hist;
    435 
    436 	/* Check for overflow when calculating sizeof_sym_hist */
    437 	if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(u64))
    438 		return -1;
    439 
    440 	sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
    441 
    442 	/* Check for overflow in zalloc argument */
    443 	if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src))
    444 				/ symbol_conf.nr_events)
    445 		return -1;
    446 
    447 	notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
    448 	if (notes->src == NULL)
    449 		return -1;
    450 	notes->src->sizeof_sym_hist = sizeof_sym_hist;
    451 	notes->src->nr_histograms   = symbol_conf.nr_events;
    452 	INIT_LIST_HEAD(&notes->src->source);
    453 	return 0;
    454 }
    455 
    456 void symbol__annotate_zero_histograms(struct symbol *sym)
    457 {
    458 	struct annotation *notes = symbol__annotation(sym);
    459 
    460 	pthread_mutex_lock(&notes->lock);
    461 	if (notes->src != NULL)
    462 		memset(notes->src->histograms, 0,
    463 		       notes->src->nr_histograms * notes->src->sizeof_sym_hist);
    464 	pthread_mutex_unlock(&notes->lock);
    465 }
    466 
    467 int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
    468 			     int evidx, u64 addr)
    469 {
    470 	unsigned offset;
    471 	struct annotation *notes;
    472 	struct sym_hist *h;
    473 
    474 	notes = symbol__annotation(sym);
    475 	if (notes->src == NULL)
    476 		return -ENOMEM;
    477 
    478 	pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
    479 
    480 	if (addr < sym->start || addr > sym->end)
    481 		return -ERANGE;
    482 
    483 	offset = addr - sym->start;
    484 	h = annotation__histogram(notes, evidx);
    485 	h->sum++;
    486 	h->addr[offset]++;
    487 
    488 	pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
    489 		  ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name,
    490 		  addr, addr - sym->start, evidx, h->addr[offset]);
    491 	return 0;
    492 }
    493 
    494 static void disasm_line__init_ins(struct disasm_line *dl)
    495 {
    496 	dl->ins = ins__find(dl->name);
    497 
    498 	if (dl->ins == NULL)
    499 		return;
    500 
    501 	if (!dl->ins->ops)
    502 		return;
    503 
    504 	if (dl->ins->ops->parse)
    505 		dl->ins->ops->parse(&dl->ops);
    506 }
    507 
    508 static int disasm_line__parse(char *line, char **namep, char **rawp)
    509 {
    510 	char *name = line, tmp;
    511 
    512 	while (isspace(name[0]))
    513 		++name;
    514 
    515 	if (name[0] == '\0')
    516 		return -1;
    517 
    518 	*rawp = name + 1;
    519 
    520 	while ((*rawp)[0] != '\0' && !isspace((*rawp)[0]))
    521 		++*rawp;
    522 
    523 	tmp = (*rawp)[0];
    524 	(*rawp)[0] = '\0';
    525 	*namep = strdup(name);
    526 
    527 	if (*namep == NULL)
    528 		goto out_free_name;
    529 
    530 	(*rawp)[0] = tmp;
    531 
    532 	if ((*rawp)[0] != '\0') {
    533 		(*rawp)++;
    534 		while (isspace((*rawp)[0]))
    535 			++(*rawp);
    536 	}
    537 
    538 	return 0;
    539 
    540 out_free_name:
    541 	free(*namep);
    542 	*namep = NULL;
    543 	return -1;
    544 }
    545 
    546 static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
    547 {
    548 	struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
    549 
    550 	if (dl != NULL) {
    551 		dl->offset = offset;
    552 		dl->line = strdup(line);
    553 		if (dl->line == NULL)
    554 			goto out_delete;
    555 
    556 		if (offset != -1) {
    557 			if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0)
    558 				goto out_free_line;
    559 
    560 			disasm_line__init_ins(dl);
    561 		}
    562 	}
    563 
    564 	return dl;
    565 
    566 out_free_line:
    567 	free(dl->line);
    568 out_delete:
    569 	free(dl);
    570 	return NULL;
    571 }
    572 
    573 void disasm_line__free(struct disasm_line *dl)
    574 {
    575 	free(dl->line);
    576 	free(dl->name);
    577 	if (dl->ins && dl->ins->ops->free)
    578 		dl->ins->ops->free(&dl->ops);
    579 	else
    580 		ins__delete(&dl->ops);
    581 	free(dl);
    582 }
    583 
    584 int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw)
    585 {
    586 	if (raw || !dl->ins)
    587 		return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw);
    588 
    589 	return ins__scnprintf(dl->ins, bf, size, &dl->ops);
    590 }
    591 
    592 static void disasm__add(struct list_head *head, struct disasm_line *line)
    593 {
    594 	list_add_tail(&line->node, head);
    595 }
    596 
    597 struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos)
    598 {
    599 	list_for_each_entry_continue(pos, head, node)
    600 		if (pos->offset >= 0)
    601 			return pos;
    602 
    603 	return NULL;
    604 }
    605 
    606 double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
    607 			    s64 end, const char **path)
    608 {
    609 	struct source_line *src_line = notes->src->lines;
    610 	double percent = 0.0;
    611 
    612 	if (src_line) {
    613 		size_t sizeof_src_line = sizeof(*src_line) +
    614 				sizeof(src_line->p) * (src_line->nr_pcnt - 1);
    615 
    616 		while (offset < end) {
    617 			src_line = (void *)notes->src->lines +
    618 					(sizeof_src_line * offset);
    619 
    620 			if (*path == NULL)
    621 				*path = src_line->path;
    622 
    623 			percent += src_line->p[evidx].percent;
    624 			offset++;
    625 		}
    626 	} else {
    627 		struct sym_hist *h = annotation__histogram(notes, evidx);
    628 		unsigned int hits = 0;
    629 
    630 		while (offset < end)
    631 			hits += h->addr[offset++];
    632 
    633 		if (h->sum)
    634 			percent = 100.0 * hits / h->sum;
    635 	}
    636 
    637 	return percent;
    638 }
    639 
    640 static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
    641 		      struct perf_evsel *evsel, u64 len, int min_pcnt, int printed,
    642 		      int max_lines, struct disasm_line *queue)
    643 {
    644 	static const char *prev_line;
    645 	static const char *prev_color;
    646 
    647 	if (dl->offset != -1) {
    648 		const char *path = NULL;
    649 		double percent, max_percent = 0.0;
    650 		double *ppercents = &percent;
    651 		int i, nr_percent = 1;
    652 		const char *color;
    653 		struct annotation *notes = symbol__annotation(sym);
    654 		s64 offset = dl->offset;
    655 		const u64 addr = start + offset;
    656 		struct disasm_line *next;
    657 
    658 		next = disasm__get_next_ip_line(&notes->src->source, dl);
    659 
    660 		if (perf_evsel__is_group_event(evsel)) {
    661 			nr_percent = evsel->nr_members;
    662 			ppercents = calloc(nr_percent, sizeof(double));
    663 			if (ppercents == NULL)
    664 				return -1;
    665 		}
    666 
    667 		for (i = 0; i < nr_percent; i++) {
    668 			percent = disasm__calc_percent(notes,
    669 					notes->src->lines ? i : evsel->idx + i,
    670 					offset,
    671 					next ? next->offset : (s64) len,
    672 					&path);
    673 
    674 			ppercents[i] = percent;
    675 			if (percent > max_percent)
    676 				max_percent = percent;
    677 		}
    678 
    679 		if (max_percent < min_pcnt)
    680 			return -1;
    681 
    682 		if (max_lines && printed >= max_lines)
    683 			return 1;
    684 
    685 		if (queue != NULL) {
    686 			list_for_each_entry_from(queue, &notes->src->source, node) {
    687 				if (queue == dl)
    688 					break;
    689 				disasm_line__print(queue, sym, start, evsel, len,
    690 						    0, 0, 1, NULL);
    691 			}
    692 		}
    693 
    694 		color = get_percent_color(max_percent);
    695 
    696 		/*
    697 		 * Also color the filename and line if needed, with
    698 		 * the same color than the percentage. Don't print it
    699 		 * twice for close colored addr with the same filename:line
    700 		 */
    701 		if (path) {
    702 			if (!prev_line || strcmp(prev_line, path)
    703 				       || color != prev_color) {
    704 				color_fprintf(stdout, color, " %s", path);
    705 				prev_line = path;
    706 				prev_color = color;
    707 			}
    708 		}
    709 
    710 		for (i = 0; i < nr_percent; i++) {
    711 			percent = ppercents[i];
    712 			color = get_percent_color(percent);
    713 			color_fprintf(stdout, color, " %7.2f", percent);
    714 		}
    715 
    716 		printf(" :	");
    717 		color_fprintf(stdout, PERF_COLOR_MAGENTA, "  %" PRIx64 ":", addr);
    718 		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
    719 
    720 		if (ppercents != &percent)
    721 			free(ppercents);
    722 
    723 	} else if (max_lines && printed >= max_lines)
    724 		return 1;
    725 	else {
    726 		int width = 8;
    727 
    728 		if (queue)
    729 			return -1;
    730 
    731 		if (perf_evsel__is_group_event(evsel))
    732 			width *= evsel->nr_members;
    733 
    734 		if (!*dl->line)
    735 			printf(" %*s:\n", width, " ");
    736 		else
    737 			printf(" %*s:	%s\n", width, " ", dl->line);
    738 	}
    739 
    740 	return 0;
    741 }
    742 
    743 /*
    744  * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw)
    745  * which looks like following
    746  *
    747  *  0000000000415500 <_init>:
    748  *    415500:       sub    $0x8,%rsp
    749  *    415504:       mov    0x2f5ad5(%rip),%rax        # 70afe0 <_DYNAMIC+0x2f8>
    750  *    41550b:       test   %rax,%rax
    751  *    41550e:       je     415515 <_init+0x15>
    752  *    415510:       callq  416e70 <__gmon_start__@plt>
    753  *    415515:       add    $0x8,%rsp
    754  *    415519:       retq
    755  *
    756  * it will be parsed and saved into struct disasm_line as
    757  *  <offset>       <name>  <ops.raw>
    758  *
    759  * The offset will be a relative offset from the start of the symbol and -1
    760  * means that it's not a disassembly line so should be treated differently.
    761  * The ops.raw part will be parsed further according to type of the instruction.
    762  */
    763 static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
    764 				      FILE *file, size_t privsize)
    765 {
    766 	struct annotation *notes = symbol__annotation(sym);
    767 	struct disasm_line *dl;
    768 	char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
    769 	size_t line_len;
    770 	s64 line_ip, offset = -1;
    771 
    772 	if (getline(&line, &line_len, file) < 0)
    773 		return -1;
    774 
    775 	if (!line)
    776 		return -1;
    777 
    778 	while (line_len != 0 && isspace(line[line_len - 1]))
    779 		line[--line_len] = '\0';
    780 
    781 	c = strchr(line, '\n');
    782 	if (c)
    783 		*c = 0;
    784 
    785 	line_ip = -1;
    786 	parsed_line = line;
    787 
    788 	/*
    789 	 * Strip leading spaces:
    790 	 */
    791 	tmp = line;
    792 	while (*tmp) {
    793 		if (*tmp != ' ')
    794 			break;
    795 		tmp++;
    796 	}
    797 
    798 	if (*tmp) {
    799 		/*
    800 		 * Parse hexa addresses followed by ':'
    801 		 */
    802 		line_ip = strtoull(tmp, &tmp2, 16);
    803 		if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
    804 			line_ip = -1;
    805 	}
    806 
    807 	if (line_ip != -1) {
    808 		u64 start = map__rip_2objdump(map, sym->start),
    809 		    end = map__rip_2objdump(map, sym->end);
    810 
    811 		offset = line_ip - start;
    812 		if ((u64)line_ip < start || (u64)line_ip > end)
    813 			offset = -1;
    814 		else
    815 			parsed_line = tmp2 + 1;
    816 	}
    817 
    818 	dl = disasm_line__new(offset, parsed_line, privsize);
    819 	free(line);
    820 
    821 	if (dl == NULL)
    822 		return -1;
    823 
    824 	if (dl->ops.target.offset == UINT64_MAX)
    825 		dl->ops.target.offset = dl->ops.target.addr -
    826 					map__rip_2objdump(map, sym->start);
    827 
    828 	/*
    829 	 * kcore has no symbols, so add the call target name if it is on the
    830 	 * same map.
    831 	 */
    832 	if (dl->ins && ins__is_call(dl->ins) && !dl->ops.target.name) {
    833 		struct symbol *s;
    834 		u64 ip = dl->ops.target.addr;
    835 
    836 		if (ip >= map->start && ip <= map->end) {
    837 			ip = map->map_ip(map, ip);
    838 			s = map__find_symbol(map, ip, NULL);
    839 			if (s && s->start == ip)
    840 				dl->ops.target.name = strdup(s->name);
    841 		}
    842 	}
    843 
    844 	disasm__add(&notes->src->source, dl);
    845 
    846 	return 0;
    847 }
    848 
    849 static void delete_last_nop(struct symbol *sym)
    850 {
    851 	struct annotation *notes = symbol__annotation(sym);
    852 	struct list_head *list = &notes->src->source;
    853 	struct disasm_line *dl;
    854 
    855 	while (!list_empty(list)) {
    856 		dl = list_entry(list->prev, struct disasm_line, node);
    857 
    858 		if (dl->ins && dl->ins->ops) {
    859 			if (dl->ins->ops != &nop_ops)
    860 				return;
    861 		} else {
    862 			if (!strstr(dl->line, " nop ") &&
    863 			    !strstr(dl->line, " nopl ") &&
    864 			    !strstr(dl->line, " nopw "))
    865 				return;
    866 		}
    867 
    868 		list_del(&dl->node);
    869 		disasm_line__free(dl);
    870 	}
    871 }
    872 
    873 int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
    874 {
    875 	struct dso *dso = map->dso;
    876 	char *filename = dso__build_id_filename(dso, NULL, 0);
    877 	bool free_filename = true;
    878 	char command[PATH_MAX * 2];
    879 	FILE *file;
    880 	int err = 0;
    881 	char symfs_filename[PATH_MAX];
    882 
    883 	if (filename) {
    884 		snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
    885 			 symbol_conf.symfs, filename);
    886 	}
    887 
    888 	if (filename == NULL) {
    889 		if (dso->has_build_id) {
    890 			pr_err("Can't annotate %s: not enough memory\n",
    891 			       sym->name);
    892 			return -ENOMEM;
    893 		}
    894 		goto fallback;
    895 	} else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
    896 		   strstr(command, "[kernel.kallsyms]") ||
    897 		   access(symfs_filename, R_OK)) {
    898 		free(filename);
    899 fallback:
    900 		/*
    901 		 * If we don't have build-ids or the build-id file isn't in the
    902 		 * cache, or is just a kallsyms file, well, lets hope that this
    903 		 * DSO is the same as when 'perf record' ran.
    904 		 */
    905 		filename = dso->long_name;
    906 		snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
    907 			 symbol_conf.symfs, filename);
    908 		free_filename = false;
    909 	}
    910 
    911 	if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
    912 	    !dso__is_kcore(dso)) {
    913 		char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
    914 		char *build_id_msg = NULL;
    915 
    916 		if (dso->annotate_warned)
    917 			goto out_free_filename;
    918 
    919 		if (dso->has_build_id) {
    920 			build_id__sprintf(dso->build_id,
    921 					  sizeof(dso->build_id), bf + 15);
    922 			build_id_msg = bf;
    923 		}
    924 		err = -ENOENT;
    925 		dso->annotate_warned = 1;
    926 		pr_err("Can't annotate %s:\n\n"
    927 		       "No vmlinux file%s\nwas found in the path.\n\n"
    928 		       "Please use:\n\n"
    929 		       "  perf buildid-cache -vu vmlinux\n\n"
    930 		       "or:\n\n"
    931 		       "  --vmlinux vmlinux\n",
    932 		       sym->name, build_id_msg ?: "");
    933 		goto out_free_filename;
    934 	}
    935 
    936 	pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
    937 		 filename, sym->name, map->unmap_ip(map, sym->start),
    938 		 map->unmap_ip(map, sym->end));
    939 
    940 	pr_debug("annotating [%p] %30s : [%p] %30s\n",
    941 		 dso, dso->long_name, sym, sym->name);
    942 
    943 	snprintf(command, sizeof(command),
    944 		 "%s %s%s --start-address=0x%016" PRIx64
    945 		 " --stop-address=0x%016" PRIx64
    946 		 " -d %s %s -C %s 2>/dev/null|grep -v %s|expand",
    947 		 objdump_path ? objdump_path : "objdump",
    948 		 disassembler_style ? "-M " : "",
    949 		 disassembler_style ? disassembler_style : "",
    950 		 map__rip_2objdump(map, sym->start),
    951 		 map__rip_2objdump(map, sym->end+1),
    952 		 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
    953 		 symbol_conf.annotate_src ? "-S" : "",
    954 		 symfs_filename, filename);
    955 
    956 	pr_debug("Executing: %s\n", command);
    957 
    958 	file = popen(command, "r");
    959 	if (!file)
    960 		goto out_free_filename;
    961 
    962 	while (!feof(file))
    963 		if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
    964 			break;
    965 
    966 	/*
    967 	 * kallsyms does not have symbol sizes so there may a nop at the end.
    968 	 * Remove it.
    969 	 */
    970 	if (dso__is_kcore(dso))
    971 		delete_last_nop(sym);
    972 
    973 	pclose(file);
    974 out_free_filename:
    975 	if (free_filename)
    976 		free(filename);
    977 	return err;
    978 }
    979 
    980 static void insert_source_line(struct rb_root *root, struct source_line *src_line)
    981 {
    982 	struct source_line *iter;
    983 	struct rb_node **p = &root->rb_node;
    984 	struct rb_node *parent = NULL;
    985 	int i, ret;
    986 
    987 	while (*p != NULL) {
    988 		parent = *p;
    989 		iter = rb_entry(parent, struct source_line, node);
    990 
    991 		ret = strcmp(iter->path, src_line->path);
    992 		if (ret == 0) {
    993 			for (i = 0; i < src_line->nr_pcnt; i++)
    994 				iter->p[i].percent_sum += src_line->p[i].percent;
    995 			return;
    996 		}
    997 
    998 		if (ret < 0)
    999 			p = &(*p)->rb_left;
   1000 		else
   1001 			p = &(*p)->rb_right;
   1002 	}
   1003 
   1004 	for (i = 0; i < src_line->nr_pcnt; i++)
   1005 		src_line->p[i].percent_sum = src_line->p[i].percent;
   1006 
   1007 	rb_link_node(&src_line->node, parent, p);
   1008 	rb_insert_color(&src_line->node, root);
   1009 }
   1010 
   1011 static int cmp_source_line(struct source_line *a, struct source_line *b)
   1012 {
   1013 	int i;
   1014 
   1015 	for (i = 0; i < a->nr_pcnt; i++) {
   1016 		if (a->p[i].percent_sum == b->p[i].percent_sum)
   1017 			continue;
   1018 		return a->p[i].percent_sum > b->p[i].percent_sum;
   1019 	}
   1020 
   1021 	return 0;
   1022 }
   1023 
   1024 static void __resort_source_line(struct rb_root *root, struct source_line *src_line)
   1025 {
   1026 	struct source_line *iter;
   1027 	struct rb_node **p = &root->rb_node;
   1028 	struct rb_node *parent = NULL;
   1029 
   1030 	while (*p != NULL) {
   1031 		parent = *p;
   1032 		iter = rb_entry(parent, struct source_line, node);
   1033 
   1034 		if (cmp_source_line(src_line, iter))
   1035 			p = &(*p)->rb_left;
   1036 		else
   1037 			p = &(*p)->rb_right;
   1038 	}
   1039 
   1040 	rb_link_node(&src_line->node, parent, p);
   1041 	rb_insert_color(&src_line->node, root);
   1042 }
   1043 
   1044 static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root)
   1045 {
   1046 	struct source_line *src_line;
   1047 	struct rb_node *node;
   1048 
   1049 	node = rb_first(src_root);
   1050 	while (node) {
   1051 		struct rb_node *next;
   1052 
   1053 		src_line = rb_entry(node, struct source_line, node);
   1054 		next = rb_next(node);
   1055 		rb_erase(node, src_root);
   1056 
   1057 		__resort_source_line(dest_root, src_line);
   1058 		node = next;
   1059 	}
   1060 }
   1061 
   1062 static void symbol__free_source_line(struct symbol *sym, int len)
   1063 {
   1064 	struct annotation *notes = symbol__annotation(sym);
   1065 	struct source_line *src_line = notes->src->lines;
   1066 	size_t sizeof_src_line;
   1067 	int i;
   1068 
   1069 	sizeof_src_line = sizeof(*src_line) +
   1070 			  (sizeof(src_line->p) * (src_line->nr_pcnt - 1));
   1071 
   1072 	for (i = 0; i < len; i++) {
   1073 		free(src_line->path);
   1074 		src_line = (void *)src_line + sizeof_src_line;
   1075 	}
   1076 
   1077 	free(notes->src->lines);
   1078 	notes->src->lines = NULL;
   1079 }
   1080 
   1081 /* Get the filename:line for the colored entries */
   1082 static int symbol__get_source_line(struct symbol *sym, struct map *map,
   1083 				   struct perf_evsel *evsel,
   1084 				   struct rb_root *root, int len,
   1085 				   const char *filename)
   1086 {
   1087 	u64 start;
   1088 	int i, k;
   1089 	int evidx = evsel->idx;
   1090 	char cmd[PATH_MAX * 2];
   1091 	struct source_line *src_line;
   1092 	struct annotation *notes = symbol__annotation(sym);
   1093 	struct sym_hist *h = annotation__histogram(notes, evidx);
   1094 	struct rb_root tmp_root = RB_ROOT;
   1095 	int nr_pcnt = 1;
   1096 	u64 h_sum = h->sum;
   1097 	size_t sizeof_src_line = sizeof(struct source_line);
   1098 
   1099 	if (perf_evsel__is_group_event(evsel)) {
   1100 		for (i = 1; i < evsel->nr_members; i++) {
   1101 			h = annotation__histogram(notes, evidx + i);
   1102 			h_sum += h->sum;
   1103 		}
   1104 		nr_pcnt = evsel->nr_members;
   1105 		sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->p);
   1106 	}
   1107 
   1108 	if (!h_sum)
   1109 		return 0;
   1110 
   1111 	src_line = notes->src->lines = calloc(len, sizeof_src_line);
   1112 	if (!notes->src->lines)
   1113 		return -1;
   1114 
   1115 	start = map__rip_2objdump(map, sym->start);
   1116 
   1117 	for (i = 0; i < len; i++) {
   1118 		char *path = NULL;
   1119 		size_t line_len;
   1120 		u64 offset;
   1121 		FILE *fp;
   1122 		double percent_max = 0.0;
   1123 
   1124 		src_line->nr_pcnt = nr_pcnt;
   1125 
   1126 		for (k = 0; k < nr_pcnt; k++) {
   1127 			h = annotation__histogram(notes, evidx + k);
   1128 			src_line->p[k].percent = 100.0 * h->addr[i] / h->sum;
   1129 
   1130 			if (src_line->p[k].percent > percent_max)
   1131 				percent_max = src_line->p[k].percent;
   1132 		}
   1133 
   1134 		if (percent_max <= 0.5)
   1135 			goto next;
   1136 
   1137 		offset = start + i;
   1138 		sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
   1139 		fp = popen(cmd, "r");
   1140 		if (!fp)
   1141 			goto next;
   1142 
   1143 		if (getline(&path, &line_len, fp) < 0 || !line_len)
   1144 			goto next_close;
   1145 
   1146 		src_line->path = malloc(sizeof(char) * line_len + 1);
   1147 		if (!src_line->path)
   1148 			goto next_close;
   1149 
   1150 		strcpy(src_line->path, path);
   1151 		insert_source_line(&tmp_root, src_line);
   1152 
   1153 	next_close:
   1154 		pclose(fp);
   1155 	next:
   1156 		src_line = (void *)src_line + sizeof_src_line;
   1157 	}
   1158 
   1159 	resort_source_line(root, &tmp_root);
   1160 	return 0;
   1161 }
   1162 
   1163 static void print_summary(struct rb_root *root, const char *filename)
   1164 {
   1165 	struct source_line *src_line;
   1166 	struct rb_node *node;
   1167 
   1168 	printf("\nSorted summary for file %s\n", filename);
   1169 	printf("----------------------------------------------\n\n");
   1170 
   1171 	if (RB_EMPTY_ROOT(root)) {
   1172 		printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
   1173 		return;
   1174 	}
   1175 
   1176 	node = rb_first(root);
   1177 	while (node) {
   1178 		double percent, percent_max = 0.0;
   1179 		const char *color;
   1180 		char *path;
   1181 		int i;
   1182 
   1183 		src_line = rb_entry(node, struct source_line, node);
   1184 		for (i = 0; i < src_line->nr_pcnt; i++) {
   1185 			percent = src_line->p[i].percent_sum;
   1186 			color = get_percent_color(percent);
   1187 			color_fprintf(stdout, color, " %7.2f", percent);
   1188 
   1189 			if (percent > percent_max)
   1190 				percent_max = percent;
   1191 		}
   1192 
   1193 		path = src_line->path;
   1194 		color = get_percent_color(percent_max);
   1195 		color_fprintf(stdout, color, " %s", path);
   1196 
   1197 		node = rb_next(node);
   1198 	}
   1199 }
   1200 
   1201 static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel)
   1202 {
   1203 	struct annotation *notes = symbol__annotation(sym);
   1204 	struct sym_hist *h = annotation__histogram(notes, evsel->idx);
   1205 	u64 len = symbol__size(sym), offset;
   1206 
   1207 	for (offset = 0; offset < len; ++offset)
   1208 		if (h->addr[offset] != 0)
   1209 			printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
   1210 			       sym->start + offset, h->addr[offset]);
   1211 	printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
   1212 }
   1213 
   1214 int symbol__annotate_printf(struct symbol *sym, struct map *map,
   1215 			    struct perf_evsel *evsel, bool full_paths,
   1216 			    int min_pcnt, int max_lines, int context)
   1217 {
   1218 	struct dso *dso = map->dso;
   1219 	char *filename;
   1220 	const char *d_filename;
   1221 	struct annotation *notes = symbol__annotation(sym);
   1222 	struct disasm_line *pos, *queue = NULL;
   1223 	u64 start = map__rip_2objdump(map, sym->start);
   1224 	int printed = 2, queue_len = 0;
   1225 	int more = 0;
   1226 	u64 len;
   1227 	int width = 8;
   1228 	int namelen;
   1229 
   1230 	filename = strdup(dso->long_name);
   1231 	if (!filename)
   1232 		return -ENOMEM;
   1233 
   1234 	if (full_paths)
   1235 		d_filename = filename;
   1236 	else
   1237 		d_filename = basename(filename);
   1238 
   1239 	len = symbol__size(sym);
   1240 	namelen = strlen(d_filename);
   1241 
   1242 	if (perf_evsel__is_group_event(evsel))
   1243 		width *= evsel->nr_members;
   1244 
   1245 	printf(" %-*.*s|	Source code & Disassembly of %s\n",
   1246 	       width, width, "Percent", d_filename);
   1247 	printf("-%-*.*s-------------------------------------\n",
   1248 	       width+namelen, width+namelen, graph_dotted_line);
   1249 
   1250 	if (verbose)
   1251 		symbol__annotate_hits(sym, evsel);
   1252 
   1253 	list_for_each_entry(pos, &notes->src->source, node) {
   1254 		if (context && queue == NULL) {
   1255 			queue = pos;
   1256 			queue_len = 0;
   1257 		}
   1258 
   1259 		switch (disasm_line__print(pos, sym, start, evsel, len,
   1260 					    min_pcnt, printed, max_lines,
   1261 					    queue)) {
   1262 		case 0:
   1263 			++printed;
   1264 			if (context) {
   1265 				printed += queue_len;
   1266 				queue = NULL;
   1267 				queue_len = 0;
   1268 			}
   1269 			break;
   1270 		case 1:
   1271 			/* filtered by max_lines */
   1272 			++more;
   1273 			break;
   1274 		case -1:
   1275 		default:
   1276 			/*
   1277 			 * Filtered by min_pcnt or non IP lines when
   1278 			 * context != 0
   1279 			 */
   1280 			if (!context)
   1281 				break;
   1282 			if (queue_len == context)
   1283 				queue = list_entry(queue->node.next, typeof(*queue), node);
   1284 			else
   1285 				++queue_len;
   1286 			break;
   1287 		}
   1288 	}
   1289 
   1290 	free(filename);
   1291 
   1292 	return more;
   1293 }
   1294 
   1295 void symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
   1296 {
   1297 	struct annotation *notes = symbol__annotation(sym);
   1298 	struct sym_hist *h = annotation__histogram(notes, evidx);
   1299 
   1300 	memset(h, 0, notes->src->sizeof_sym_hist);
   1301 }
   1302 
   1303 void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
   1304 {
   1305 	struct annotation *notes = symbol__annotation(sym);
   1306 	struct sym_hist *h = annotation__histogram(notes, evidx);
   1307 	int len = symbol__size(sym), offset;
   1308 
   1309 	h->sum = 0;
   1310 	for (offset = 0; offset < len; ++offset) {
   1311 		h->addr[offset] = h->addr[offset] * 7 / 8;
   1312 		h->sum += h->addr[offset];
   1313 	}
   1314 }
   1315 
   1316 void disasm__purge(struct list_head *head)
   1317 {
   1318 	struct disasm_line *pos, *n;
   1319 
   1320 	list_for_each_entry_safe(pos, n, head, node) {
   1321 		list_del(&pos->node);
   1322 		disasm_line__free(pos);
   1323 	}
   1324 }
   1325 
   1326 static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
   1327 {
   1328 	size_t printed;
   1329 
   1330 	if (dl->offset == -1)
   1331 		return fprintf(fp, "%s\n", dl->line);
   1332 
   1333 	printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name);
   1334 
   1335 	if (dl->ops.raw[0] != '\0') {
   1336 		printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
   1337 				   dl->ops.raw);
   1338 	}
   1339 
   1340 	return printed + fprintf(fp, "\n");
   1341 }
   1342 
   1343 size_t disasm__fprintf(struct list_head *head, FILE *fp)
   1344 {
   1345 	struct disasm_line *pos;
   1346 	size_t printed = 0;
   1347 
   1348 	list_for_each_entry(pos, head, node)
   1349 		printed += disasm_line__fprintf(pos, fp);
   1350 
   1351 	return printed;
   1352 }
   1353 
   1354 int symbol__tty_annotate(struct symbol *sym, struct map *map,
   1355 			 struct perf_evsel *evsel, bool print_lines,
   1356 			 bool full_paths, int min_pcnt, int max_lines)
   1357 {
   1358 	struct dso *dso = map->dso;
   1359 	const char *filename = dso->long_name;
   1360 	struct rb_root source_line = RB_ROOT;
   1361 	u64 len;
   1362 
   1363 	if (symbol__annotate(sym, map, 0) < 0)
   1364 		return -1;
   1365 
   1366 	len = symbol__size(sym);
   1367 
   1368 	if (print_lines) {
   1369 		symbol__get_source_line(sym, map, evsel, &source_line,
   1370 					len, filename);
   1371 		print_summary(&source_line, filename);
   1372 	}
   1373 
   1374 	symbol__annotate_printf(sym, map, evsel, full_paths,
   1375 				min_pcnt, max_lines, 0);
   1376 	if (print_lines)
   1377 		symbol__free_source_line(sym, len);
   1378 
   1379 	disasm__purge(&symbol__annotation(sym)->src->source);
   1380 
   1381 	return 0;
   1382 }
   1383