annotate.c 20.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
 *
 * Parts came from builtin-annotate.c, see those files for further
 * copyright notes.
 *
 * Released under the GPL v2. (and only v2, not any later version)
 */

#include "util.h"
#include "build-id.h"
#include "color.h"
#include "cache.h"
#include "symbol.h"
#include "debug.h"
#include "annotate.h"
17
#include <pthread.h>
18

19 20
const char 	*disassembler_style;

21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
			      struct ins_operands *ops)
{
	return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw);
}

int ins__scnprintf(struct ins *ins, char *bf, size_t size,
		  struct ins_operands *ops)
{
	if (ins->ops->scnprintf)
		return ins->ops->scnprintf(ins, bf, size, ops);

	return ins__raw_scnprintf(ins, bf, size, ops);
}

36
static int call__parse(struct ins_operands *ops)
37
{
38 39
	char *endptr, *tok, *name;

40
	ops->target.addr = strtoull(ops->raw, &endptr, 16);
41 42 43 44 45 46 47 48 49 50 51 52

	name = strchr(endptr, '<');
	if (name == NULL)
		goto indirect_call;

	name++;

	tok = strchr(name, '>');
	if (tok == NULL)
		return -1;

	*tok = '\0';
53
	ops->target.name = strdup(name);
54 55
	*tok = '>';

56
	return ops->target.name == NULL ? -1 : 0;
57 58

indirect_call:
59 60 61 62 63 64
	tok = strchr(endptr, '(');
	if (tok != NULL) {
		ops->target.addr = 0;
		return 0;
	}

65 66 67 68
	tok = strchr(endptr, '*');
	if (tok == NULL)
		return -1;

69
	ops->target.addr = strtoull(tok + 1, NULL, 16);
70 71 72
	return 0;
}

73
static int call__scnprintf(struct ins *ins, char *bf, size_t size,
74
			   struct ins_operands *ops)
75
{
76 77
	if (ops->target.name)
		return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name);
78

79 80 81
	if (ops->target.addr == 0)
		return ins__raw_scnprintf(ins, bf, size, ops);

82
	return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr);
83 84
}

85
static struct ins_ops call_ops = {
86 87
	.parse	   = call__parse,
	.scnprintf = call__scnprintf,
88 89 90 91 92 93 94
};

bool ins__is_call(const struct ins *ins)
{
	return ins->ops == &call_ops;
}

95
static int jump__parse(struct ins_operands *ops)
96
{
97
	const char *s = strchr(ops->raw, '+');
98

99 100 101 102 103 104
	ops->target.addr = strtoll(ops->raw, NULL, 16);

	if (s++ != NULL)
		ops->target.offset = strtoll(s, NULL, 16);
	else
		ops->target.offset = UINT64_MAX;
105 106 107 108

	return 0;
}

109
static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
110
			   struct ins_operands *ops)
111
{
112
	return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset);
113 114
}

115
static struct ins_ops jump_ops = {
116 117
	.parse	   = jump__parse,
	.scnprintf = jump__scnprintf,
118 119 120 121 122 123 124
};

bool ins__is_jump(const struct ins *ins)
{
	return ins->ops == &jump_ops;
}

125 126 127 128 129 130 131 132 133 134
static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size,
			  struct ins_operands *ops __used)
{
	return scnprintf(bf, size, "%-6.6s", "nop");
}

static struct ins_ops nop_ops = {
	.scnprintf = nop__scnprintf,
};

135 136 137 138
/*
 * Must be sorted by name!
 */
static struct ins instructions[] = {
139 140
	{ .name = "call",  .ops  = &call_ops, },
	{ .name = "callq", .ops  = &call_ops, },
141
	{ .name = "ja",	   .ops  = &jump_ops, },
142 143 144 145 146
	{ .name = "jae",   .ops  = &jump_ops, },
	{ .name = "jb",	   .ops  = &jump_ops, },
	{ .name = "jbe",   .ops  = &jump_ops, },
	{ .name = "jc",	   .ops  = &jump_ops, },
	{ .name = "jcxz",  .ops  = &jump_ops, },
147
	{ .name = "je",	   .ops  = &jump_ops, },
148 149 150 151 152
	{ .name = "jecxz", .ops  = &jump_ops, },
	{ .name = "jg",	   .ops  = &jump_ops, },
	{ .name = "jge",   .ops  = &jump_ops, },
	{ .name = "jl",    .ops  = &jump_ops, },
	{ .name = "jle",   .ops  = &jump_ops, },
153 154
	{ .name = "jmp",   .ops  = &jump_ops, },
	{ .name = "jmpq",  .ops  = &jump_ops, },
155 156 157 158 159
	{ .name = "jna",   .ops  = &jump_ops, },
	{ .name = "jnae",  .ops  = &jump_ops, },
	{ .name = "jnb",   .ops  = &jump_ops, },
	{ .name = "jnbe",  .ops  = &jump_ops, },
	{ .name = "jnc",   .ops  = &jump_ops, },
160
	{ .name = "jne",   .ops  = &jump_ops, },
161 162 163 164 165 166 167 168 169 170 171 172 173
	{ .name = "jng",   .ops  = &jump_ops, },
	{ .name = "jnge",  .ops  = &jump_ops, },
	{ .name = "jnl",   .ops  = &jump_ops, },
	{ .name = "jnle",  .ops  = &jump_ops, },
	{ .name = "jno",   .ops  = &jump_ops, },
	{ .name = "jnp",   .ops  = &jump_ops, },
	{ .name = "jns",   .ops  = &jump_ops, },
	{ .name = "jnz",   .ops  = &jump_ops, },
	{ .name = "jo",	   .ops  = &jump_ops, },
	{ .name = "jp",	   .ops  = &jump_ops, },
	{ .name = "jpe",   .ops  = &jump_ops, },
	{ .name = "jpo",   .ops  = &jump_ops, },
	{ .name = "jrcxz", .ops  = &jump_ops, },
174
	{ .name = "js",	   .ops  = &jump_ops, },
175
	{ .name = "jz",	   .ops  = &jump_ops, },
176 177 178
	{ .name = "nop",   .ops  = &nop_ops, },
	{ .name = "nopl",  .ops  = &nop_ops, },
	{ .name = "nopw",  .ops  = &nop_ops, },
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
};

static int ins__cmp(const void *name, const void *insp)
{
	const struct ins *ins = insp;

	return strcmp(name, ins->name);
}

static struct ins *ins__find(const char *name)
{
	const int nmemb = ARRAY_SIZE(instructions);

	return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp);
}

195
int symbol__annotate_init(struct map *map __used, struct symbol *sym)
196 197
{
	struct annotation *notes = symbol__annotation(sym);
198 199 200
	pthread_mutex_init(&notes->lock, NULL);
	return 0;
}
201

202
int symbol__alloc_hist(struct symbol *sym)
203 204
{
	struct annotation *notes = symbol__annotation(sym);
205
	const size_t size = symbol__size(sym);
206
	size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
207

208
	notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
209 210 211
	if (notes->src == NULL)
		return -1;
	notes->src->sizeof_sym_hist = sizeof_sym_hist;
212
	notes->src->nr_histograms   = symbol_conf.nr_events;
213 214
	INIT_LIST_HEAD(&notes->src->source);
	return 0;
215 216
}

217 218 219 220
void symbol__annotate_zero_histograms(struct symbol *sym)
{
	struct annotation *notes = symbol__annotation(sym);

221 222 223 224 225
	pthread_mutex_lock(&notes->lock);
	if (notes->src != NULL)
		memset(notes->src->histograms, 0,
		       notes->src->nr_histograms * notes->src->sizeof_sym_hist);
	pthread_mutex_unlock(&notes->lock);
226 227
}

228 229
int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
			     int evidx, u64 addr)
230
{
231
	unsigned offset;
232 233 234 235
	struct annotation *notes;
	struct sym_hist *h;

	notes = symbol__annotation(sym);
236
	if (notes->src == NULL)
237 238 239 240
		return -ENOMEM;

	pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));

241 242
	if (addr < sym->start || addr > sym->end)
		return -ERANGE;
243

244 245
	offset = addr - sym->start;
	h = annotation__histogram(notes, evidx);
246 247 248 249
	h->sum++;
	h->addr[offset]++;

	pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
250 251
		  ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name,
		  addr, addr - sym->start, evidx, h->addr[offset]);
252 253 254
	return 0;
}

255 256 257 258 259 260 261 262 263 264
static void disasm_line__init_ins(struct disasm_line *dl)
{
	dl->ins = ins__find(dl->name);

	if (dl->ins == NULL)
		return;

	if (!dl->ins->ops)
		return;

265 266
	if (dl->ins->ops->parse)
		dl->ins->ops->parse(&dl->ops);
267 268
}

269
static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
270
{
271
	struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
272

273 274 275 276
	if (dl != NULL) {
		dl->offset = offset;
		dl->line = strdup(line);
		if (dl->line == NULL)
277
			goto out_delete;
278 279 280 281 282 283 284 285 286 287

		if (offset != -1) {
			char *name = dl->line, tmp;

			while (isspace(name[0]))
				++name;

			if (name[0] == '\0')
				goto out_delete;

288
			dl->ops.raw = name + 1;
289

290 291 292
			while (dl->ops.raw[0] != '\0' &&
			       !isspace(dl->ops.raw[0]))
				++dl->ops.raw;
293

294 295
			tmp = dl->ops.raw[0];
			dl->ops.raw[0] = '\0';
296 297 298 299 300
			dl->name = strdup(name);

			if (dl->name == NULL)
				goto out_free_line;

301
			dl->ops.raw[0] = tmp;
302

303 304 305 306
			if (dl->ops.raw[0] != '\0') {
				dl->ops.raw++;
				while (isspace(dl->ops.raw[0]))
					++dl->ops.raw;
307
			}
308 309

			disasm_line__init_ins(dl);
310
		}
311 312
	}

313
	return dl;
314 315 316

out_free_line:
	free(dl->line);
317
out_delete:
318
	free(dl);
319
	return NULL;
320 321
}

322
void disasm_line__free(struct disasm_line *dl)
323
{
324
	free(dl->line);
325
	free(dl->name);
326
	free(dl->ops.target.name);
327
	free(dl);
328 329
}

330 331 332 333 334 335 336 337
int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw)
{
	if (raw || !dl->ins)
		return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw);

	return ins__scnprintf(dl->ins, bf, size, &dl->ops);
}

338
static void disasm__add(struct list_head *head, struct disasm_line *line)
339 340 341 342
{
	list_add_tail(&line->node, head);
}

343
struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos)
344 345 346 347 348 349 350 351
{
	list_for_each_entry_continue(pos, head, node)
		if (pos->offset >= 0)
			return pos;

	return NULL;
}

352 353 354
static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
		      int evidx, u64 len, int min_pcnt, int printed,
		      int max_lines, struct disasm_line *queue)
355 356 357 358
{
	static const char *prev_line;
	static const char *prev_color;

359
	if (dl->offset != -1) {
360 361 362 363 364
		const char *path = NULL;
		unsigned int hits = 0;
		double percent = 0.0;
		const char *color;
		struct annotation *notes = symbol__annotation(sym);
365
		struct source_line *src_line = notes->src->lines;
366
		struct sym_hist *h = annotation__histogram(notes, evidx);
367
		s64 offset = dl->offset;
368
		const u64 addr = start + offset;
369
		struct disasm_line *next;
370

371
		next = disasm__get_next_ip_line(&notes->src->source, dl);
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387

		while (offset < (s64)len &&
		       (next == NULL || offset < next->offset)) {
			if (src_line) {
				if (path == NULL)
					path = src_line[offset].path;
				percent += src_line[offset].percent;
			} else
				hits += h->addr[offset];

			++offset;
		}

		if (src_line == NULL && h->sum)
			percent = 100.0 * hits / h->sum;

388
		if (percent < min_pcnt)
389 390
			return -1;

391
		if (max_lines && printed >= max_lines)
392
			return 1;
393

394 395
		if (queue != NULL) {
			list_for_each_entry_from(queue, &notes->src->source, node) {
396
				if (queue == dl)
397
					break;
398
				disasm_line__print(queue, sym, start, evidx, len,
399 400 401 402
						    0, 0, 1, NULL);
			}
		}

403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
		color = get_percent_color(percent);

		/*
		 * Also color the filename and line if needed, with
		 * the same color than the percentage. Don't print it
		 * twice for close colored addr with the same filename:line
		 */
		if (path) {
			if (!prev_line || strcmp(prev_line, path)
				       || color != prev_color) {
				color_fprintf(stdout, color, " %s", path);
				prev_line = path;
				prev_color = color;
			}
		}

		color_fprintf(stdout, color, " %7.2f", percent);
		printf(" :	");
421
		color_fprintf(stdout, PERF_COLOR_MAGENTA, "  %" PRIx64 ":", addr);
422
		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
423
	} else if (max_lines && printed >= max_lines)
424 425
		return 1;
	else {
426 427 428
		if (queue)
			return -1;

429
		if (!*dl->line)
430 431
			printf("         :\n");
		else
432
			printf("         :	%s\n", dl->line);
433
	}
434 435

	return 0;
436 437
}

438 439
static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
				      FILE *file, size_t privsize)
440
{
441
	struct annotation *notes = symbol__annotation(sym);
442
	struct disasm_line *dl;
443
	char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
	size_t line_len;
	s64 line_ip, offset = -1;

	if (getline(&line, &line_len, file) < 0)
		return -1;

	if (!line)
		return -1;

	while (line_len != 0 && isspace(line[line_len - 1]))
		line[--line_len] = '\0';

	c = strchr(line, '\n');
	if (c)
		*c = 0;

	line_ip = -1;
N
Namhyung Kim 已提交
461
	parsed_line = line;
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488

	/*
	 * Strip leading spaces:
	 */
	tmp = line;
	while (*tmp) {
		if (*tmp != ' ')
			break;
		tmp++;
	}

	if (*tmp) {
		/*
		 * Parse hexa addresses followed by ':'
		 */
		line_ip = strtoull(tmp, &tmp2, 16);
		if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
			line_ip = -1;
	}

	if (line_ip != -1) {
		u64 start = map__rip_2objdump(map, sym->start),
		    end = map__rip_2objdump(map, sym->end);

		offset = line_ip - start;
		if (offset < 0 || (u64)line_ip > end)
			offset = -1;
489 490
		else
			parsed_line = tmp2 + 1;
N
Namhyung Kim 已提交
491
	}
492

493
	dl = disasm_line__new(offset, parsed_line, privsize);
494 495
	free(line);

496
	if (dl == NULL)
497
		return -1;
498

499
	disasm__add(&notes->src->source, dl);
500 501 502 503

	return 0;
}

504
int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
{
	struct dso *dso = map->dso;
	char *filename = dso__build_id_filename(dso, NULL, 0);
	bool free_filename = true;
	char command[PATH_MAX * 2];
	FILE *file;
	int err = 0;
	char symfs_filename[PATH_MAX];

	if (filename) {
		snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
			 symbol_conf.symfs, filename);
	}

	if (filename == NULL) {
		if (dso->has_build_id) {
			pr_err("Can't annotate %s: not enough memory\n",
			       sym->name);
			return -ENOMEM;
		}
		goto fallback;
	} else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
		   strstr(command, "[kernel.kallsyms]") ||
		   access(symfs_filename, R_OK)) {
		free(filename);
fallback:
		/*
		 * If we don't have build-ids or the build-id file isn't in the
		 * cache, or is just a kallsyms file, well, lets hope that this
		 * DSO is the same as when 'perf record' ran.
		 */
		filename = dso->long_name;
		snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
			 symbol_conf.symfs, filename);
		free_filename = false;
	}

542
	if (dso->symtab_type == SYMTAB__KALLSYMS) {
543 544 545
		char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
		char *build_id_msg = NULL;

546 547
		if (dso->annotate_warned)
			goto out_free_filename;
548 549 550 551 552 553

		if (dso->has_build_id) {
			build_id__sprintf(dso->build_id,
					  sizeof(dso->build_id), bf + 15);
			build_id_msg = bf;
		}
554 555
		err = -ENOENT;
		dso->annotate_warned = 1;
556 557 558 559 560
		pr_err("Can't annotate %s:\n\n"
		       "No vmlinux file%s\nwas found in the path.\n\n"
		       "Please use:\n\n"
		       "  perf buildid-cache -av vmlinux\n\n"
		       "or:\n\n"
561
		       "  --vmlinux vmlinux\n",
562
		       sym->name, build_id_msg ?: "");
563 564 565 566 567 568 569 570 571 572 573
		goto out_free_filename;
	}

	pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
		 filename, sym->name, map->unmap_ip(map, sym->start),
		 map->unmap_ip(map, sym->end));

	pr_debug("annotating [%p] %30s : [%p] %30s\n",
		 dso, dso->long_name, sym, sym->name);

	snprintf(command, sizeof(command),
574
		 "objdump %s%s --start-address=0x%016" PRIx64
575 576
		 " --stop-address=0x%016" PRIx64
		 " -d %s %s -C %s|grep -v %s|expand",
577 578
		 disassembler_style ? "-M " : "",
		 disassembler_style ? disassembler_style : "",
579
		 map__rip_2objdump(map, sym->start),
I
Ingo Molnar 已提交
580
		 map__rip_2objdump(map, sym->end+1),
581 582
		 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
		 symbol_conf.annotate_src ? "-S" : "",
583 584 585 586 587 588 589 590 591
		 symfs_filename, filename);

	pr_debug("Executing: %s\n", command);

	file = popen(command, "r");
	if (!file)
		goto out_free_filename;

	while (!feof(file))
592
		if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
			break;

	pclose(file);
out_free_filename:
	if (free_filename)
		free(filename);
	return err;
}

static void insert_source_line(struct rb_root *root, struct source_line *src_line)
{
	struct source_line *iter;
	struct rb_node **p = &root->rb_node;
	struct rb_node *parent = NULL;

	while (*p != NULL) {
		parent = *p;
		iter = rb_entry(parent, struct source_line, node);

		if (src_line->percent > iter->percent)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

	rb_link_node(&src_line->node, parent, p);
	rb_insert_color(&src_line->node, root);
}

static void symbol__free_source_line(struct symbol *sym, int len)
{
	struct annotation *notes = symbol__annotation(sym);
625
	struct source_line *src_line = notes->src->lines;
626 627 628 629 630 631
	int i;

	for (i = 0; i < len; i++)
		free(src_line[i].path);

	free(src_line);
632
	notes->src->lines = NULL;
633 634 635 636
}

/* Get the filename:line for the colored entries */
static int symbol__get_source_line(struct symbol *sym, struct map *map,
637
				   int evidx, struct rb_root *root, int len,
638 639 640 641 642 643 644
				   const char *filename)
{
	u64 start;
	int i;
	char cmd[PATH_MAX * 2];
	struct source_line *src_line;
	struct annotation *notes = symbol__annotation(sym);
645
	struct sym_hist *h = annotation__histogram(notes, evidx);
646 647 648 649

	if (!h->sum)
		return 0;

650 651
	src_line = notes->src->lines = calloc(len, sizeof(struct source_line));
	if (!notes->src->lines)
652 653
		return -1;

654
	start = map__rip_2objdump(map, sym->start);
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717

	for (i = 0; i < len; i++) {
		char *path = NULL;
		size_t line_len;
		u64 offset;
		FILE *fp;

		src_line[i].percent = 100.0 * h->addr[i] / h->sum;
		if (src_line[i].percent <= 0.5)
			continue;

		offset = start + i;
		sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
		fp = popen(cmd, "r");
		if (!fp)
			continue;

		if (getline(&path, &line_len, fp) < 0 || !line_len)
			goto next;

		src_line[i].path = malloc(sizeof(char) * line_len + 1);
		if (!src_line[i].path)
			goto next;

		strcpy(src_line[i].path, path);
		insert_source_line(root, &src_line[i]);

	next:
		pclose(fp);
	}

	return 0;
}

static void print_summary(struct rb_root *root, const char *filename)
{
	struct source_line *src_line;
	struct rb_node *node;

	printf("\nSorted summary for file %s\n", filename);
	printf("----------------------------------------------\n\n");

	if (RB_EMPTY_ROOT(root)) {
		printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
		return;
	}

	node = rb_first(root);
	while (node) {
		double percent;
		const char *color;
		char *path;

		src_line = rb_entry(node, struct source_line, node);
		percent = src_line->percent;
		color = get_percent_color(percent);
		path = src_line->path;

		color_fprintf(stdout, color, " %7.2f %s", percent, path);
		node = rb_next(node);
	}
}

718
static void symbol__annotate_hits(struct symbol *sym, int evidx)
719 720
{
	struct annotation *notes = symbol__annotation(sym);
721
	struct sym_hist *h = annotation__histogram(notes, evidx);
722
	u64 len = symbol__size(sym), offset;
723 724 725 726 727 728 729 730

	for (offset = 0; offset < len; ++offset)
		if (h->addr[offset] != 0)
			printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
			       sym->start + offset, h->addr[offset]);
	printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
}

731
int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
732 733
			    bool full_paths, int min_pcnt, int max_lines,
			    int context)
734 735 736
{
	struct dso *dso = map->dso;
	const char *filename = dso->long_name, *d_filename;
737
	struct annotation *notes = symbol__annotation(sym);
738
	struct disasm_line *pos, *queue = NULL;
739
	u64 start = map__rip_2objdump(map, sym->start);
740
	int printed = 2, queue_len = 0;
741
	int more = 0;
742 743 744 745 746 747 748
	u64 len;

	if (full_paths)
		d_filename = filename;
	else
		d_filename = basename(filename);

749
	len = symbol__size(sym);
750 751 752 753 754

	printf(" Percent |	Source code & Disassembly of %s\n", d_filename);
	printf("------------------------------------------------\n");

	if (verbose)
755
		symbol__annotate_hits(sym, evidx);
756

757
	list_for_each_entry(pos, &notes->src->source, node) {
758 759 760 761 762
		if (context && queue == NULL) {
			queue = pos;
			queue_len = 0;
		}

763
		switch (disasm_line__print(pos, sym, start, evidx, len,
764 765
					    min_pcnt, printed, max_lines,
					    queue)) {
766 767
		case 0:
			++printed;
768 769 770 771 772
			if (context) {
				printed += queue_len;
				queue = NULL;
				queue_len = 0;
			}
773 774 775 776
			break;
		case 1:
			/* filtered by max_lines */
			++more;
777
			break;
778 779
		case -1:
		default:
780 781 782 783 784 785 786 787 788 789
			/*
			 * Filtered by min_pcnt or non IP lines when
			 * context != 0
			 */
			if (!context)
				break;
			if (queue_len == context)
				queue = list_entry(queue->node.next, typeof(*queue), node);
			else
				++queue_len;
790 791 792 793 794 795
			break;
		}
	}

	return more;
}
796

797 798 799 800 801
void symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
{
	struct annotation *notes = symbol__annotation(sym);
	struct sym_hist *h = annotation__histogram(notes, evidx);

802
	memset(h, 0, notes->src->sizeof_sym_hist);
803 804
}

805
void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
806 807 808
{
	struct annotation *notes = symbol__annotation(sym);
	struct sym_hist *h = annotation__histogram(notes, evidx);
809
	int len = symbol__size(sym), offset;
810 811

	h->sum = 0;
812 813 814
	for (offset = 0; offset < len; ++offset) {
		h->addr[offset] = h->addr[offset] * 7 / 8;
		h->sum += h->addr[offset];
815 816 817
	}
}

818
void disasm__purge(struct list_head *head)
819
{
820
	struct disasm_line *pos, *n;
821 822 823

	list_for_each_entry_safe(pos, n, head, node) {
		list_del(&pos->node);
824
		disasm_line__free(pos);
825 826 827
	}
}

828 829 830 831 832 833 834 835 836
static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
{
	size_t printed;

	if (dl->offset == -1)
		return fprintf(fp, "%s\n", dl->line);

	printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name);

837
	if (dl->ops.raw[0] != '\0') {
838
		printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
839
				   dl->ops.raw);
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
	}

	return printed + fprintf(fp, "\n");
}

size_t disasm__fprintf(struct list_head *head, FILE *fp)
{
	struct disasm_line *pos;
	size_t printed = 0;

	list_for_each_entry(pos, head, node)
		printed += disasm_line__fprintf(pos, fp);

	return printed;
}

856 857 858 859 860 861 862 863 864
int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
			 bool print_lines, bool full_paths, int min_pcnt,
			 int max_lines)
{
	struct dso *dso = map->dso;
	const char *filename = dso->long_name;
	struct rb_root source_line = RB_ROOT;
	u64 len;

865
	if (symbol__annotate(sym, map, 0) < 0)
866 867
		return -1;

868
	len = symbol__size(sym);
869 870 871 872 873

	if (print_lines) {
		symbol__get_source_line(sym, map, evidx, &source_line,
					len, filename);
		print_summary(&source_line, filename);
874 875
	}

876
	symbol__annotate_printf(sym, map, evidx, full_paths,
877
				min_pcnt, max_lines, 0);
878 879 880
	if (print_lines)
		symbol__free_source_line(sym, len);

881
	disasm__purge(&symbol__annotation(sym)->src->source);
882

883 884
	return 0;
}